From 34b7393388962e9d3a769f80917ff205efc86b21 Mon Sep 17 00:00:00 2001 From: Isaku Yamahata Date: Thu, 26 Jun 2014 16:04:55 +0900 Subject: [PATCH] remove unnecessary neutron files under neutron/plugins Change-Id: Ia27aa8af3701b740ea6750560f96fbf9ec704465 --- neutron/plugins/bigswitch/README | 14 - neutron/plugins/bigswitch/__init__.py | 16 - neutron/plugins/bigswitch/agent/__init__.py | 0 .../bigswitch/agent/restproxy_agent.py | 181 -- neutron/plugins/bigswitch/config.py | 123 - neutron/plugins/bigswitch/db/__init__.py | 18 - .../plugins/bigswitch/db/consistency_db.py | 56 - .../plugins/bigswitch/db/porttracker_db.py | 53 - .../plugins/bigswitch/extensions/__init__.py | 18 - .../bigswitch/extensions/routerrule.py | 144 - neutron/plugins/bigswitch/plugin.py | 1115 -------- neutron/plugins/bigswitch/routerrule_db.py | 148 - neutron/plugins/bigswitch/servermanager.py | 595 ---- neutron/plugins/bigswitch/tests/__init__.py | 16 - .../plugins/bigswitch/tests/test_server.py | 188 -- neutron/plugins/bigswitch/vcsversion.py | 27 - neutron/plugins/bigswitch/version.py | 53 - neutron/plugins/brocade/NeutronPlugin.py | 497 ---- neutron/plugins/brocade/README.md | 112 - neutron/plugins/brocade/__init__.py | 16 - neutron/plugins/brocade/db/__init__.py | 16 - neutron/plugins/brocade/db/models.py | 151 - neutron/plugins/brocade/nos/__init__.py | 16 - neutron/plugins/brocade/nos/fake_nosdriver.py | 117 - neutron/plugins/brocade/nos/nctemplates.py | 204 -- neutron/plugins/brocade/nos/nosdriver.py | 233 -- neutron/plugins/brocade/tests/README | 24 - neutron/plugins/brocade/tests/noscli.py | 93 - neutron/plugins/brocade/tests/nostest.py | 48 - neutron/plugins/brocade/vlanbm.py | 60 - neutron/plugins/cisco/README | 7 - neutron/plugins/cisco/__init__.py | 18 - neutron/plugins/cisco/common/__init__.py | 17 - .../plugins/cisco/common/cisco_constants.py | 111 - .../cisco/common/cisco_credentials_v2.py | 61 - .../plugins/cisco/common/cisco_exceptions.py | 236 -- neutron/plugins/cisco/common/cisco_faults.py | 138 - neutron/plugins/cisco/common/config.py | 151 - neutron/plugins/cisco/db/__init__.py | 18 - neutron/plugins/cisco/db/n1kv_db_v2.py | 1621 ----------- neutron/plugins/cisco/db/n1kv_models_v2.py | 185 -- neutron/plugins/cisco/db/network_db_v2.py | 290 -- neutron/plugins/cisco/db/network_models_v2.py | 56 - neutron/plugins/cisco/db/nexus_db_v2.py | 154 - neutron/plugins/cisco/db/nexus_models_v2.py | 46 - neutron/plugins/cisco/extensions/__init__.py | 16 - .../cisco/extensions/_credential_view.py | 52 - neutron/plugins/cisco/extensions/_qos_view.py | 52 - .../plugins/cisco/extensions/credential.py | 84 - neutron/plugins/cisco/extensions/n1kv.py | 106 - .../cisco/extensions/network_profile.py | 103 - .../cisco/extensions/policy_profile.py | 85 - neutron/plugins/cisco/extensions/qos.py | 156 - neutron/plugins/cisco/l2device_plugin_base.py | 175 -- neutron/plugins/cisco/models/__init__.py | 17 - .../plugins/cisco/models/virt_phy_sw_v2.py | 553 ---- neutron/plugins/cisco/n1kv/__init__.py | 18 - neutron/plugins/cisco/n1kv/n1kv_client.py | 541 ---- .../plugins/cisco/n1kv/n1kv_neutron_plugin.py | 1438 ---------- neutron/plugins/cisco/network_plugin.py | 176 -- neutron/plugins/cisco/nexus/__init__.py | 21 - .../nexus/cisco_nexus_network_driver_v2.py | 196 -- .../cisco/nexus/cisco_nexus_plugin_v2.py | 347 --- .../cisco/nexus/cisco_nexus_snippets.py | 180 -- neutron/plugins/cisco/test/__init__.py | 0 neutron/plugins/cisco/test/nexus/__init__.py | 19 - .../cisco/test/nexus/fake_nexus_driver.py | 101 - neutron/plugins/embrane/README | 9 - neutron/plugins/embrane/__init__.py | 18 - neutron/plugins/embrane/agent/__init__.py | 18 - neutron/plugins/embrane/agent/dispatcher.py | 134 - .../embrane/agent/operations/__init__.py | 18 - .../agent/operations/router_operations.py | 156 - neutron/plugins/embrane/base_plugin.py | 375 --- neutron/plugins/embrane/common/__init__.py | 18 - neutron/plugins/embrane/common/config.py | 49 - neutron/plugins/embrane/common/constants.py | 72 - neutron/plugins/embrane/common/contexts.py | 40 - neutron/plugins/embrane/common/exceptions.py | 28 - neutron/plugins/embrane/common/operation.py | 51 - neutron/plugins/embrane/common/utils.py | 73 - neutron/plugins/embrane/l2base/__init__.py | 18 - .../plugins/embrane/l2base/fake/__init__.py | 18 - .../embrane/l2base/fake/fake_l2_plugin.py | 24 - .../embrane/l2base/fake/fakeplugin_support.py | 45 - .../embrane/l2base/openvswitch/__init__.py | 18 - .../l2base/openvswitch/openvswitch_support.py | 58 - .../plugins/embrane/l2base/support_base.py | 50 - .../embrane/l2base/support_exceptions.py | 25 - neutron/plugins/embrane/plugins/__init__.py | 18 - .../embrane/plugins/embrane_fake_plugin.py | 34 - .../embrane/plugins/embrane_ovs_plugin.py | 38 - neutron/plugins/hyperv/__init__.py | 16 - neutron/plugins/hyperv/agent/__init__.py | 16 - .../hyperv/agent/hyperv_neutron_agent.py | 475 ---- .../hyperv/agent/security_groups_driver.py | 146 - neutron/plugins/hyperv/agent/utils.py | 256 -- neutron/plugins/hyperv/agent/utilsfactory.py | 72 - neutron/plugins/hyperv/agent/utilsv2.py | 439 --- neutron/plugins/hyperv/agent_notifier_api.py | 80 - neutron/plugins/hyperv/common/__init__.py | 16 - neutron/plugins/hyperv/common/constants.py | 23 - neutron/plugins/hyperv/db.py | 219 -- .../plugins/hyperv/hyperv_neutron_plugin.py | 333 --- neutron/plugins/hyperv/model.py | 55 - neutron/plugins/hyperv/rpc_callbacks.py | 94 - neutron/plugins/ibm/README | 6 - neutron/plugins/ibm/__init__.py | 0 neutron/plugins/ibm/agent/__init__.py | 0 .../plugins/ibm/agent/sdnve_neutron_agent.py | 270 -- neutron/plugins/ibm/common/__init__.py | 0 neutron/plugins/ibm/common/config.py | 74 - neutron/plugins/ibm/common/constants.py | 32 - neutron/plugins/ibm/common/exceptions.py | 28 - neutron/plugins/ibm/sdnve_api.py | 388 --- neutron/plugins/ibm/sdnve_api_fake.py | 64 - neutron/plugins/ibm/sdnve_neutron_plugin.py | 666 ----- neutron/plugins/linuxbridge/README | 169 -- neutron/plugins/linuxbridge/__init__.py | 0 neutron/plugins/linuxbridge/agent/__init__.py | 0 .../agent/linuxbridge_neutron_agent.py | 1026 ------- .../plugins/linuxbridge/common/__init__.py | 17 - neutron/plugins/linuxbridge/common/config.py | 78 - .../plugins/linuxbridge/common/constants.py | 42 - neutron/plugins/linuxbridge/db/__init__.py | 18 - .../plugins/linuxbridge/db/l2network_db_v2.py | 238 -- .../linuxbridge/db/l2network_models_v2.py | 59 - .../plugins/linuxbridge/lb_neutron_plugin.py | 530 ---- neutron/plugins/metaplugin/README | 92 - neutron/plugins/metaplugin/__init__.py | 16 - neutron/plugins/metaplugin/common/__init__.py | 16 - neutron/plugins/metaplugin/common/config.py | 80 - neutron/plugins/metaplugin/meta_db_v2.py | 52 - neutron/plugins/metaplugin/meta_models_v2.py | 43 - .../plugins/metaplugin/meta_neutron_plugin.py | 419 --- .../metaplugin/proxy_neutron_plugin.py | 136 - neutron/plugins/midonet/__init__.py | 17 - neutron/plugins/midonet/agent/__init__.py | 16 - .../plugins/midonet/agent/midonet_driver.py | 52 - neutron/plugins/midonet/common/__init__.py | 16 - neutron/plugins/midonet/common/config.py | 46 - neutron/plugins/midonet/common/net_util.py | 68 - neutron/plugins/midonet/midonet_lib.py | 696 ----- neutron/plugins/midonet/plugin.py | 1258 -------- neutron/plugins/ml2/README | 53 - neutron/plugins/ml2/__init__.py | 14 - neutron/plugins/ml2/common/__init__.py | 14 - neutron/plugins/ml2/common/exceptions.py | 23 - neutron/plugins/ml2/config.py | 36 - neutron/plugins/ml2/db.py | 136 - neutron/plugins/ml2/driver_api.py | 597 ---- neutron/plugins/ml2/driver_context.py | 135 - neutron/plugins/ml2/drivers/README.fslsdn | 102 - neutron/plugins/ml2/drivers/README.odl | 41 - neutron/plugins/ml2/drivers/__init__.py | 14 - neutron/plugins/ml2/drivers/brocade/README.md | 60 - .../plugins/ml2/drivers/brocade/__init__.py | 0 .../ml2/drivers/brocade/db/__init__.py | 0 .../plugins/ml2/drivers/brocade/db/models.py | 139 - .../ml2/drivers/brocade/mechanism_brocade.py | 385 --- .../ml2/drivers/brocade/nos/__init__.py | 0 .../ml2/drivers/brocade/nos/nctemplates.py | 197 -- .../ml2/drivers/brocade/nos/nosdriver.py | 236 -- neutron/plugins/ml2/drivers/cisco/__init__.py | 14 - .../ml2/drivers/cisco/apic/__init__.py | 0 .../ml2/drivers/cisco/apic/apic_client.py | 416 --- .../ml2/drivers/cisco/apic/apic_manager.py | 559 ---- .../ml2/drivers/cisco/apic/apic_model.py | 177 -- .../plugins/ml2/drivers/cisco/apic/config.py | 82 - .../ml2/drivers/cisco/apic/exceptions.py | 59 - .../ml2/drivers/cisco/apic/mechanism_apic.py | 150 - .../plugins/ml2/drivers/cisco/nexus/README | 19 - .../ml2/drivers/cisco/nexus/__init__.py | 0 .../plugins/ml2/drivers/cisco/nexus/config.py | 65 - .../ml2/drivers/cisco/nexus/constants.py | 24 - .../ml2/drivers/cisco/nexus/exceptions.py | 84 - .../drivers/cisco/nexus/mech_cisco_nexus.py | 219 -- .../ml2/drivers/cisco/nexus/nexus_db_v2.py | 143 - .../drivers/cisco/nexus/nexus_models_v2.py | 45 - .../cisco/nexus/nexus_network_driver.py | 171 -- .../ml2/drivers/cisco/nexus/nexus_snippets.py | 200 -- neutron/plugins/ml2/drivers/l2pop/README | 41 - neutron/plugins/ml2/drivers/l2pop/__init__.py | 18 - neutron/plugins/ml2/drivers/l2pop/config.py | 29 - .../plugins/ml2/drivers/l2pop/constants.py | 23 - neutron/plugins/ml2/drivers/l2pop/db.py | 83 - .../plugins/ml2/drivers/l2pop/mech_driver.py | 248 -- neutron/plugins/ml2/drivers/l2pop/rpc.py | 86 - neutron/plugins/ml2/drivers/mech_agent.py | 149 - .../plugins/ml2/drivers/mech_arista/README | 9 - .../ml2/drivers/mech_arista/__init__.py | 14 - .../plugins/ml2/drivers/mech_arista/config.py | 70 - neutron/plugins/ml2/drivers/mech_arista/db.py | 402 --- .../ml2/drivers/mech_arista/exceptions.py | 27 - .../drivers/mech_arista/mechanism_arista.py | 1014 ------- .../ml2/drivers/mech_bigswitch/__init__.py | 0 .../ml2/drivers/mech_bigswitch/driver.py | 130 - neutron/plugins/ml2/drivers/mech_hyperv.py | 57 - .../plugins/ml2/drivers/mech_linuxbridge.py | 57 - neutron/plugins/ml2/drivers/mech_ofagent.py | 61 - .../plugins/ml2/drivers/mech_openvswitch.py | 58 - .../plugins/ml2/drivers/mechanism_fslsdn.py | 288 -- neutron/plugins/ml2/drivers/mechanism_ncs.py | 182 -- neutron/plugins/ml2/drivers/mechanism_odl.py | 374 --- neutron/plugins/ml2/drivers/mlnx/__init__.py | 0 neutron/plugins/ml2/drivers/mlnx/config.py | 32 - neutron/plugins/ml2/drivers/mlnx/mech_mlnx.py | 91 - neutron/plugins/ml2/drivers/type_flat.py | 131 - neutron/plugins/ml2/drivers/type_gre.py | 190 -- neutron/plugins/ml2/drivers/type_local.py | 59 - neutron/plugins/ml2/drivers/type_tunnel.py | 132 - neutron/plugins/ml2/drivers/type_vlan.py | 267 -- neutron/plugins/ml2/drivers/type_vxlan.py | 203 -- neutron/plugins/ml2/managers.py | 480 ---- neutron/plugins/ml2/models.py | 76 - neutron/plugins/ml2/plugin.py | 791 ------ neutron/plugins/ml2/rpc.py | 239 -- neutron/plugins/mlnx/README | 8 - neutron/plugins/mlnx/__init__.py | 16 - neutron/plugins/mlnx/agent/__init__.py | 16 - .../mlnx/agent/eswitch_neutron_agent.py | 438 --- neutron/plugins/mlnx/agent/utils.py | 144 - neutron/plugins/mlnx/agent_notify_api.py | 67 - neutron/plugins/mlnx/common/__init__.py | 16 - neutron/plugins/mlnx/common/comm_utils.py | 66 - neutron/plugins/mlnx/common/config.py | 80 - neutron/plugins/mlnx/common/constants.py | 28 - neutron/plugins/mlnx/common/exceptions.py | 30 - neutron/plugins/mlnx/db/__init__.py | 16 - neutron/plugins/mlnx/db/mlnx_db_v2.py | 257 -- neutron/plugins/mlnx/db/mlnx_models_v2.py | 86 - neutron/plugins/mlnx/mlnx_plugin.py | 512 ---- neutron/plugins/mlnx/rpc_callbacks.py | 119 - neutron/plugins/nec/README | 13 - neutron/plugins/nec/__init__.py | 15 - neutron/plugins/nec/agent/__init__.py | 15 - .../plugins/nec/agent/nec_neutron_agent.py | 252 -- neutron/plugins/nec/common/__init__.py | 15 - neutron/plugins/nec/common/config.py | 84 - neutron/plugins/nec/common/constants.py | 24 - neutron/plugins/nec/common/exceptions.py | 85 - neutron/plugins/nec/common/ofc_client.py | 158 -- neutron/plugins/nec/common/utils.py | 24 - neutron/plugins/nec/db/__init__.py | 15 - neutron/plugins/nec/db/api.py | 186 -- neutron/plugins/nec/db/models.py | 71 - neutron/plugins/nec/db/packetfilter.py | 220 -- neutron/plugins/nec/db/router.py | 92 - neutron/plugins/nec/drivers/__init__.py | 40 - neutron/plugins/nec/drivers/pfc.py | 374 --- neutron/plugins/nec/drivers/trema.py | 250 -- neutron/plugins/nec/extensions/__init__.py | 15 - .../plugins/nec/extensions/packetfilter.py | 208 -- .../plugins/nec/extensions/router_provider.py | 60 - neutron/plugins/nec/nec_plugin.py | 781 ----- neutron/plugins/nec/nec_router.py | 358 --- neutron/plugins/nec/ofc_driver_base.py | 105 - neutron/plugins/nec/ofc_manager.py | 201 -- neutron/plugins/nec/packet_filter.py | 258 -- neutron/plugins/nec/router_drivers.py | 224 -- neutron/plugins/nuage/__init__.py | 0 neutron/plugins/nuage/common/__init__.py | 0 neutron/plugins/nuage/common/config.py | 47 - neutron/plugins/nuage/common/constants.py | 28 - neutron/plugins/nuage/common/exceptions.py | 24 - neutron/plugins/nuage/extensions/__init__.py | 0 .../plugins/nuage/extensions/netpartition.py | 107 - .../plugins/nuage/extensions/nuage_router.py | 73 - .../plugins/nuage/extensions/nuage_subnet.py | 59 - neutron/plugins/nuage/nuage_models.py | 102 - neutron/plugins/nuage/nuagedb.py | 202 -- neutron/plugins/nuage/plugin.py | 1006 ------- neutron/plugins/ofagent/README | 21 - neutron/plugins/ofagent/__init__.py | 0 neutron/plugins/ofagent/agent/__init__.py | 0 .../ofagent/agent/ofa_neutron_agent.py | 1418 --------- neutron/plugins/ofagent/common/__init__.py | 0 neutron/plugins/ofagent/common/config.py | 33 - neutron/plugins/oneconvergence/README | 32 - neutron/plugins/oneconvergence/__init__.py | 0 .../plugins/oneconvergence/agent/__init__.py | 0 .../agent/nvsd_neutron_agent.py | 176 -- .../plugins/oneconvergence/lib/__init__.py | 0 neutron/plugins/oneconvergence/lib/config.py | 57 - .../plugins/oneconvergence/lib/exception.py | 55 - neutron/plugins/oneconvergence/lib/nvsd_db.py | 45 - neutron/plugins/oneconvergence/lib/nvsdlib.py | 352 --- .../oneconvergence/lib/plugin_helper.py | 186 -- neutron/plugins/oneconvergence/plugin.py | 440 --- neutron/plugins/openvswitch/README | 6 - neutron/plugins/openvswitch/__init__.py | 0 neutron/plugins/openvswitch/agent/__init__.py | 0 .../openvswitch/agent/ovs_neutron_agent.py | 1517 ---------- .../plugins/openvswitch/agent/xenapi/README | 16 - .../agent/xenapi/contrib/build-rpm.sh | 34 - .../SPECS/openstack-quantum-xen-plugins.spec | 30 - .../agent/xenapi/etc/xapi.d/plugins/netwrap | 72 - .../plugins/openvswitch/common/__init__.py | 15 - neutron/plugins/openvswitch/common/config.py | 94 - .../plugins/openvswitch/common/constants.py | 54 - neutron/plugins/openvswitch/ovs_db_v2.py | 396 --- neutron/plugins/openvswitch/ovs_models_v2.py | 107 - .../plugins/openvswitch/ovs_neutron_plugin.py | 623 ---- neutron/plugins/plumgrid/README | 8 - neutron/plugins/plumgrid/__init__.py | 17 - neutron/plugins/plumgrid/common/__init__.py | 17 - neutron/plugins/plumgrid/common/exceptions.py | 30 - neutron/plugins/plumgrid/drivers/__init__.py | 16 - .../plugins/plumgrid/drivers/fake_plumlib.py | 99 - neutron/plugins/plumgrid/drivers/plumlib.py | 100 - .../plumgrid/plumgrid_plugin/__init__.py | 17 - .../plumgrid/plumgrid_plugin/plugin_ver.py | 19 - .../plumgrid_plugin/plumgrid_plugin.py | 604 ---- neutron/plugins/ryu/README | 22 - neutron/plugins/ryu/__init__.py | 0 neutron/plugins/ryu/agent/__init__.py | 0 .../plugins/ryu/agent/ryu_neutron_agent.py | 314 -- neutron/plugins/ryu/common/__init__.py | 15 - neutron/plugins/ryu/common/config.py | 52 - neutron/plugins/ryu/db/__init__.py | 0 neutron/plugins/ryu/db/api_v2.py | 215 -- neutron/plugins/ryu/db/models_v2.py | 41 - neutron/plugins/ryu/ryu_neutron_plugin.py | 269 -- neutron/plugins/vmware/__init__.py | 3 - neutron/plugins/vmware/api_client/__init__.py | 29 - neutron/plugins/vmware/api_client/base.py | 249 -- neutron/plugins/vmware/api_client/client.py | 143 - .../vmware/api_client/eventlet_client.py | 155 - .../vmware/api_client/eventlet_request.py | 240 -- .../plugins/vmware/api_client/exception.py | 121 - neutron/plugins/vmware/api_client/request.py | 287 -- neutron/plugins/vmware/api_client/version.py | 43 - neutron/plugins/vmware/check_nsx_config.py | 163 -- neutron/plugins/vmware/common/__init__.py | 0 neutron/plugins/vmware/common/config.py | 198 -- neutron/plugins/vmware/common/exceptions.py | 126 - neutron/plugins/vmware/common/nsx_utils.py | 249 -- .../plugins/vmware/common/securitygroups.py | 134 - neutron/plugins/vmware/common/sync.py | 669 ----- neutron/plugins/vmware/common/utils.py | 69 - neutron/plugins/vmware/dbexts/__init__.py | 0 neutron/plugins/vmware/dbexts/db.py | 193 -- .../vmware/dbexts/distributedrouter.py | 28 - neutron/plugins/vmware/dbexts/lsn_db.py | 131 - neutron/plugins/vmware/dbexts/maclearning.py | 78 - neutron/plugins/vmware/dbexts/models.py | 135 - neutron/plugins/vmware/dbexts/networkgw_db.py | 499 ---- neutron/plugins/vmware/dbexts/nsxrouter.py | 66 - neutron/plugins/vmware/dbexts/qos_db.py | 297 -- .../plugins/vmware/dbexts/servicerouter.py | 27 - neutron/plugins/vmware/dbexts/vcns_db.py | 202 -- neutron/plugins/vmware/dbexts/vcns_models.py | 90 - neutron/plugins/vmware/dhcp_meta/__init__.py | 16 - neutron/plugins/vmware/dhcp_meta/combined.py | 95 - neutron/plugins/vmware/dhcp_meta/constants.py | 28 - .../plugins/vmware/dhcp_meta/lsnmanager.py | 462 --- neutron/plugins/vmware/dhcp_meta/migration.py | 180 -- neutron/plugins/vmware/dhcp_meta/nsx.py | 321 --- neutron/plugins/vmware/dhcp_meta/rpc.py | 222 -- neutron/plugins/vmware/dhcpmeta_modes.py | 163 -- neutron/plugins/vmware/extensions/__init__.py | 0 .../vmware/extensions/distributedrouter.py | 70 - neutron/plugins/vmware/extensions/lsn.py | 82 - .../plugins/vmware/extensions/maclearning.py | 61 - .../plugins/vmware/extensions/networkgw.py | 251 -- neutron/plugins/vmware/extensions/nvp_qos.py | 40 - neutron/plugins/vmware/extensions/qos.py | 223 -- .../vmware/extensions/servicerouter.py | 59 - neutron/plugins/vmware/nsx_cluster.py | 97 - neutron/plugins/vmware/nsxlib/__init__.py | 141 - neutron/plugins/vmware/nsxlib/l2gateway.py | 211 -- neutron/plugins/vmware/nsxlib/lsn.py | 270 -- neutron/plugins/vmware/nsxlib/queue.py | 71 - neutron/plugins/vmware/nsxlib/router.py | 689 ----- neutron/plugins/vmware/nsxlib/secgroup.py | 141 - neutron/plugins/vmware/nsxlib/switch.py | 397 --- neutron/plugins/vmware/nsxlib/versioning.py | 66 - neutron/plugins/vmware/plugin.py | 22 - neutron/plugins/vmware/plugins/__init__.py | 0 neutron/plugins/vmware/plugins/base.py | 2528 ----------------- neutron/plugins/vmware/plugins/service.py | 1812 ------------ neutron/plugins/vmware/shell/__init__.py | 41 - neutron/plugins/vmware/shell/commands.py | 67 - neutron/plugins/vmware/vshield/__init__.py | 16 - .../vmware/vshield/common/VcnsApiClient.py | 80 - .../plugins/vmware/vshield/common/__init__.py | 0 .../vmware/vshield/common/constants.py | 45 - .../vmware/vshield/common/exceptions.py | 70 - .../vmware/vshield/edge_appliance_driver.py | 667 ----- .../vmware/vshield/edge_firewall_driver.py | 354 --- .../vmware/vshield/edge_ipsecvpn_driver.py | 150 - .../vshield/edge_loadbalancer_driver.py | 403 --- .../plugins/vmware/vshield/tasks/__init__.py | 0 .../plugins/vmware/vshield/tasks/constants.py | 44 - neutron/plugins/vmware/vshield/tasks/tasks.py | 397 --- neutron/plugins/vmware/vshield/vcns.py | 304 -- neutron/plugins/vmware/vshield/vcns_driver.py | 53 - 397 files changed, 64347 deletions(-) delete mode 100644 neutron/plugins/bigswitch/README delete mode 100644 neutron/plugins/bigswitch/__init__.py delete mode 100644 neutron/plugins/bigswitch/agent/__init__.py delete mode 100644 neutron/plugins/bigswitch/agent/restproxy_agent.py delete mode 100644 neutron/plugins/bigswitch/config.py delete mode 100644 neutron/plugins/bigswitch/db/__init__.py delete mode 100644 neutron/plugins/bigswitch/db/consistency_db.py delete mode 100644 neutron/plugins/bigswitch/db/porttracker_db.py delete mode 100644 neutron/plugins/bigswitch/extensions/__init__.py delete mode 100644 neutron/plugins/bigswitch/extensions/routerrule.py delete mode 100644 neutron/plugins/bigswitch/plugin.py delete mode 100644 neutron/plugins/bigswitch/routerrule_db.py delete mode 100644 neutron/plugins/bigswitch/servermanager.py delete mode 100644 neutron/plugins/bigswitch/tests/__init__.py delete mode 100755 neutron/plugins/bigswitch/tests/test_server.py delete mode 100644 neutron/plugins/bigswitch/vcsversion.py delete mode 100755 neutron/plugins/bigswitch/version.py delete mode 100644 neutron/plugins/brocade/NeutronPlugin.py delete mode 100644 neutron/plugins/brocade/README.md delete mode 100644 neutron/plugins/brocade/__init__.py delete mode 100644 neutron/plugins/brocade/db/__init__.py delete mode 100644 neutron/plugins/brocade/db/models.py delete mode 100644 neutron/plugins/brocade/nos/__init__.py delete mode 100644 neutron/plugins/brocade/nos/fake_nosdriver.py delete mode 100644 neutron/plugins/brocade/nos/nctemplates.py delete mode 100644 neutron/plugins/brocade/nos/nosdriver.py delete mode 100644 neutron/plugins/brocade/tests/README delete mode 100644 neutron/plugins/brocade/tests/noscli.py delete mode 100644 neutron/plugins/brocade/tests/nostest.py delete mode 100644 neutron/plugins/brocade/vlanbm.py delete mode 100644 neutron/plugins/cisco/README delete mode 100644 neutron/plugins/cisco/__init__.py delete mode 100644 neutron/plugins/cisco/common/__init__.py delete mode 100644 neutron/plugins/cisco/common/cisco_constants.py delete mode 100644 neutron/plugins/cisco/common/cisco_credentials_v2.py delete mode 100644 neutron/plugins/cisco/common/cisco_exceptions.py delete mode 100644 neutron/plugins/cisco/common/cisco_faults.py delete mode 100644 neutron/plugins/cisco/common/config.py delete mode 100644 neutron/plugins/cisco/db/__init__.py delete mode 100644 neutron/plugins/cisco/db/n1kv_db_v2.py delete mode 100644 neutron/plugins/cisco/db/n1kv_models_v2.py delete mode 100644 neutron/plugins/cisco/db/network_db_v2.py delete mode 100644 neutron/plugins/cisco/db/network_models_v2.py delete mode 100644 neutron/plugins/cisco/db/nexus_db_v2.py delete mode 100644 neutron/plugins/cisco/db/nexus_models_v2.py delete mode 100644 neutron/plugins/cisco/extensions/__init__.py delete mode 100644 neutron/plugins/cisco/extensions/_credential_view.py delete mode 100644 neutron/plugins/cisco/extensions/_qos_view.py delete mode 100644 neutron/plugins/cisco/extensions/credential.py delete mode 100644 neutron/plugins/cisco/extensions/n1kv.py delete mode 100644 neutron/plugins/cisco/extensions/network_profile.py delete mode 100644 neutron/plugins/cisco/extensions/policy_profile.py delete mode 100644 neutron/plugins/cisco/extensions/qos.py delete mode 100644 neutron/plugins/cisco/l2device_plugin_base.py delete mode 100644 neutron/plugins/cisco/models/__init__.py delete mode 100644 neutron/plugins/cisco/models/virt_phy_sw_v2.py delete mode 100644 neutron/plugins/cisco/n1kv/__init__.py delete mode 100644 neutron/plugins/cisco/n1kv/n1kv_client.py delete mode 100644 neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py delete mode 100644 neutron/plugins/cisco/network_plugin.py delete mode 100644 neutron/plugins/cisco/nexus/__init__.py delete mode 100644 neutron/plugins/cisco/nexus/cisco_nexus_network_driver_v2.py delete mode 100644 neutron/plugins/cisco/nexus/cisco_nexus_plugin_v2.py delete mode 100644 neutron/plugins/cisco/nexus/cisco_nexus_snippets.py delete mode 100644 neutron/plugins/cisco/test/__init__.py delete mode 100644 neutron/plugins/cisco/test/nexus/__init__.py delete mode 100644 neutron/plugins/cisco/test/nexus/fake_nexus_driver.py delete mode 100644 neutron/plugins/embrane/README delete mode 100644 neutron/plugins/embrane/__init__.py delete mode 100644 neutron/plugins/embrane/agent/__init__.py delete mode 100644 neutron/plugins/embrane/agent/dispatcher.py delete mode 100644 neutron/plugins/embrane/agent/operations/__init__.py delete mode 100644 neutron/plugins/embrane/agent/operations/router_operations.py delete mode 100644 neutron/plugins/embrane/base_plugin.py delete mode 100644 neutron/plugins/embrane/common/__init__.py delete mode 100644 neutron/plugins/embrane/common/config.py delete mode 100644 neutron/plugins/embrane/common/constants.py delete mode 100644 neutron/plugins/embrane/common/contexts.py delete mode 100644 neutron/plugins/embrane/common/exceptions.py delete mode 100644 neutron/plugins/embrane/common/operation.py delete mode 100644 neutron/plugins/embrane/common/utils.py delete mode 100644 neutron/plugins/embrane/l2base/__init__.py delete mode 100644 neutron/plugins/embrane/l2base/fake/__init__.py delete mode 100644 neutron/plugins/embrane/l2base/fake/fake_l2_plugin.py delete mode 100644 neutron/plugins/embrane/l2base/fake/fakeplugin_support.py delete mode 100644 neutron/plugins/embrane/l2base/openvswitch/__init__.py delete mode 100644 neutron/plugins/embrane/l2base/openvswitch/openvswitch_support.py delete mode 100644 neutron/plugins/embrane/l2base/support_base.py delete mode 100644 neutron/plugins/embrane/l2base/support_exceptions.py delete mode 100644 neutron/plugins/embrane/plugins/__init__.py delete mode 100644 neutron/plugins/embrane/plugins/embrane_fake_plugin.py delete mode 100644 neutron/plugins/embrane/plugins/embrane_ovs_plugin.py delete mode 100644 neutron/plugins/hyperv/__init__.py delete mode 100644 neutron/plugins/hyperv/agent/__init__.py delete mode 100644 neutron/plugins/hyperv/agent/hyperv_neutron_agent.py delete mode 100644 neutron/plugins/hyperv/agent/security_groups_driver.py delete mode 100644 neutron/plugins/hyperv/agent/utils.py delete mode 100644 neutron/plugins/hyperv/agent/utilsfactory.py delete mode 100644 neutron/plugins/hyperv/agent/utilsv2.py delete mode 100644 neutron/plugins/hyperv/agent_notifier_api.py delete mode 100644 neutron/plugins/hyperv/common/__init__.py delete mode 100644 neutron/plugins/hyperv/common/constants.py delete mode 100644 neutron/plugins/hyperv/db.py delete mode 100644 neutron/plugins/hyperv/hyperv_neutron_plugin.py delete mode 100644 neutron/plugins/hyperv/model.py delete mode 100644 neutron/plugins/hyperv/rpc_callbacks.py delete mode 100644 neutron/plugins/ibm/README delete mode 100644 neutron/plugins/ibm/__init__.py delete mode 100644 neutron/plugins/ibm/agent/__init__.py delete mode 100644 neutron/plugins/ibm/agent/sdnve_neutron_agent.py delete mode 100644 neutron/plugins/ibm/common/__init__.py delete mode 100644 neutron/plugins/ibm/common/config.py delete mode 100644 neutron/plugins/ibm/common/constants.py delete mode 100644 neutron/plugins/ibm/common/exceptions.py delete mode 100644 neutron/plugins/ibm/sdnve_api.py delete mode 100644 neutron/plugins/ibm/sdnve_api_fake.py delete mode 100644 neutron/plugins/ibm/sdnve_neutron_plugin.py delete mode 100644 neutron/plugins/linuxbridge/README delete mode 100644 neutron/plugins/linuxbridge/__init__.py delete mode 100644 neutron/plugins/linuxbridge/agent/__init__.py delete mode 100755 neutron/plugins/linuxbridge/agent/linuxbridge_neutron_agent.py delete mode 100644 neutron/plugins/linuxbridge/common/__init__.py delete mode 100644 neutron/plugins/linuxbridge/common/config.py delete mode 100644 neutron/plugins/linuxbridge/common/constants.py delete mode 100644 neutron/plugins/linuxbridge/db/__init__.py delete mode 100644 neutron/plugins/linuxbridge/db/l2network_db_v2.py delete mode 100644 neutron/plugins/linuxbridge/db/l2network_models_v2.py delete mode 100644 neutron/plugins/linuxbridge/lb_neutron_plugin.py delete mode 100644 neutron/plugins/metaplugin/README delete mode 100644 neutron/plugins/metaplugin/__init__.py delete mode 100644 neutron/plugins/metaplugin/common/__init__.py delete mode 100644 neutron/plugins/metaplugin/common/config.py delete mode 100644 neutron/plugins/metaplugin/meta_db_v2.py delete mode 100644 neutron/plugins/metaplugin/meta_models_v2.py delete mode 100644 neutron/plugins/metaplugin/meta_neutron_plugin.py delete mode 100644 neutron/plugins/metaplugin/proxy_neutron_plugin.py delete mode 100644 neutron/plugins/midonet/__init__.py delete mode 100644 neutron/plugins/midonet/agent/__init__.py delete mode 100644 neutron/plugins/midonet/agent/midonet_driver.py delete mode 100644 neutron/plugins/midonet/common/__init__.py delete mode 100644 neutron/plugins/midonet/common/config.py delete mode 100644 neutron/plugins/midonet/common/net_util.py delete mode 100644 neutron/plugins/midonet/midonet_lib.py delete mode 100644 neutron/plugins/midonet/plugin.py delete mode 100644 neutron/plugins/ml2/README delete mode 100644 neutron/plugins/ml2/__init__.py delete mode 100644 neutron/plugins/ml2/common/__init__.py delete mode 100644 neutron/plugins/ml2/common/exceptions.py delete mode 100644 neutron/plugins/ml2/config.py delete mode 100644 neutron/plugins/ml2/db.py delete mode 100644 neutron/plugins/ml2/driver_api.py delete mode 100644 neutron/plugins/ml2/driver_context.py delete mode 100644 neutron/plugins/ml2/drivers/README.fslsdn delete mode 100644 neutron/plugins/ml2/drivers/README.odl delete mode 100644 neutron/plugins/ml2/drivers/__init__.py delete mode 100644 neutron/plugins/ml2/drivers/brocade/README.md delete mode 100644 neutron/plugins/ml2/drivers/brocade/__init__.py delete mode 100644 neutron/plugins/ml2/drivers/brocade/db/__init__.py delete mode 100644 neutron/plugins/ml2/drivers/brocade/db/models.py delete mode 100644 neutron/plugins/ml2/drivers/brocade/mechanism_brocade.py delete mode 100644 neutron/plugins/ml2/drivers/brocade/nos/__init__.py delete mode 100644 neutron/plugins/ml2/drivers/brocade/nos/nctemplates.py delete mode 100644 neutron/plugins/ml2/drivers/brocade/nos/nosdriver.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/__init__.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/apic/__init__.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/apic/apic_client.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/apic/apic_manager.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/apic/apic_model.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/apic/config.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/apic/exceptions.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/apic/mechanism_apic.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/nexus/README delete mode 100644 neutron/plugins/ml2/drivers/cisco/nexus/__init__.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/nexus/config.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/nexus/constants.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/nexus/exceptions.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/nexus/mech_cisco_nexus.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/nexus/nexus_db_v2.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/nexus/nexus_models_v2.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/nexus/nexus_network_driver.py delete mode 100644 neutron/plugins/ml2/drivers/cisco/nexus/nexus_snippets.py delete mode 100644 neutron/plugins/ml2/drivers/l2pop/README delete mode 100644 neutron/plugins/ml2/drivers/l2pop/__init__.py delete mode 100644 neutron/plugins/ml2/drivers/l2pop/config.py delete mode 100644 neutron/plugins/ml2/drivers/l2pop/constants.py delete mode 100644 neutron/plugins/ml2/drivers/l2pop/db.py delete mode 100644 neutron/plugins/ml2/drivers/l2pop/mech_driver.py delete mode 100644 neutron/plugins/ml2/drivers/l2pop/rpc.py delete mode 100644 neutron/plugins/ml2/drivers/mech_agent.py delete mode 100644 neutron/plugins/ml2/drivers/mech_arista/README delete mode 100644 neutron/plugins/ml2/drivers/mech_arista/__init__.py delete mode 100644 neutron/plugins/ml2/drivers/mech_arista/config.py delete mode 100644 neutron/plugins/ml2/drivers/mech_arista/db.py delete mode 100644 neutron/plugins/ml2/drivers/mech_arista/exceptions.py delete mode 100644 neutron/plugins/ml2/drivers/mech_arista/mechanism_arista.py delete mode 100644 neutron/plugins/ml2/drivers/mech_bigswitch/__init__.py delete mode 100644 neutron/plugins/ml2/drivers/mech_bigswitch/driver.py delete mode 100644 neutron/plugins/ml2/drivers/mech_hyperv.py delete mode 100644 neutron/plugins/ml2/drivers/mech_linuxbridge.py delete mode 100644 neutron/plugins/ml2/drivers/mech_ofagent.py delete mode 100644 neutron/plugins/ml2/drivers/mech_openvswitch.py delete mode 100755 neutron/plugins/ml2/drivers/mechanism_fslsdn.py delete mode 100644 neutron/plugins/ml2/drivers/mechanism_ncs.py delete mode 100644 neutron/plugins/ml2/drivers/mechanism_odl.py delete mode 100644 neutron/plugins/ml2/drivers/mlnx/__init__.py delete mode 100644 neutron/plugins/ml2/drivers/mlnx/config.py delete mode 100644 neutron/plugins/ml2/drivers/mlnx/mech_mlnx.py delete mode 100644 neutron/plugins/ml2/drivers/type_flat.py delete mode 100644 neutron/plugins/ml2/drivers/type_gre.py delete mode 100644 neutron/plugins/ml2/drivers/type_local.py delete mode 100644 neutron/plugins/ml2/drivers/type_tunnel.py delete mode 100644 neutron/plugins/ml2/drivers/type_vlan.py delete mode 100644 neutron/plugins/ml2/drivers/type_vxlan.py delete mode 100644 neutron/plugins/ml2/managers.py delete mode 100644 neutron/plugins/ml2/models.py delete mode 100644 neutron/plugins/ml2/plugin.py delete mode 100644 neutron/plugins/ml2/rpc.py delete mode 100644 neutron/plugins/mlnx/README delete mode 100644 neutron/plugins/mlnx/__init__.py delete mode 100644 neutron/plugins/mlnx/agent/__init__.py delete mode 100644 neutron/plugins/mlnx/agent/eswitch_neutron_agent.py delete mode 100644 neutron/plugins/mlnx/agent/utils.py delete mode 100644 neutron/plugins/mlnx/agent_notify_api.py delete mode 100644 neutron/plugins/mlnx/common/__init__.py delete mode 100644 neutron/plugins/mlnx/common/comm_utils.py delete mode 100644 neutron/plugins/mlnx/common/config.py delete mode 100644 neutron/plugins/mlnx/common/constants.py delete mode 100644 neutron/plugins/mlnx/common/exceptions.py delete mode 100644 neutron/plugins/mlnx/db/__init__.py delete mode 100644 neutron/plugins/mlnx/db/mlnx_db_v2.py delete mode 100644 neutron/plugins/mlnx/db/mlnx_models_v2.py delete mode 100644 neutron/plugins/mlnx/mlnx_plugin.py delete mode 100644 neutron/plugins/mlnx/rpc_callbacks.py delete mode 100644 neutron/plugins/nec/README delete mode 100644 neutron/plugins/nec/__init__.py delete mode 100644 neutron/plugins/nec/agent/__init__.py delete mode 100755 neutron/plugins/nec/agent/nec_neutron_agent.py delete mode 100644 neutron/plugins/nec/common/__init__.py delete mode 100644 neutron/plugins/nec/common/config.py delete mode 100644 neutron/plugins/nec/common/constants.py delete mode 100644 neutron/plugins/nec/common/exceptions.py delete mode 100644 neutron/plugins/nec/common/ofc_client.py delete mode 100644 neutron/plugins/nec/common/utils.py delete mode 100644 neutron/plugins/nec/db/__init__.py delete mode 100644 neutron/plugins/nec/db/api.py delete mode 100644 neutron/plugins/nec/db/models.py delete mode 100644 neutron/plugins/nec/db/packetfilter.py delete mode 100644 neutron/plugins/nec/db/router.py delete mode 100644 neutron/plugins/nec/drivers/__init__.py delete mode 100644 neutron/plugins/nec/drivers/pfc.py delete mode 100644 neutron/plugins/nec/drivers/trema.py delete mode 100644 neutron/plugins/nec/extensions/__init__.py delete mode 100644 neutron/plugins/nec/extensions/packetfilter.py delete mode 100644 neutron/plugins/nec/extensions/router_provider.py delete mode 100644 neutron/plugins/nec/nec_plugin.py delete mode 100644 neutron/plugins/nec/nec_router.py delete mode 100644 neutron/plugins/nec/ofc_driver_base.py delete mode 100644 neutron/plugins/nec/ofc_manager.py delete mode 100644 neutron/plugins/nec/packet_filter.py delete mode 100644 neutron/plugins/nec/router_drivers.py delete mode 100644 neutron/plugins/nuage/__init__.py delete mode 100644 neutron/plugins/nuage/common/__init__.py delete mode 100644 neutron/plugins/nuage/common/config.py delete mode 100644 neutron/plugins/nuage/common/constants.py delete mode 100644 neutron/plugins/nuage/common/exceptions.py delete mode 100644 neutron/plugins/nuage/extensions/__init__.py delete mode 100644 neutron/plugins/nuage/extensions/netpartition.py delete mode 100644 neutron/plugins/nuage/extensions/nuage_router.py delete mode 100644 neutron/plugins/nuage/extensions/nuage_subnet.py delete mode 100644 neutron/plugins/nuage/nuage_models.py delete mode 100644 neutron/plugins/nuage/nuagedb.py delete mode 100644 neutron/plugins/nuage/plugin.py delete mode 100644 neutron/plugins/ofagent/README delete mode 100644 neutron/plugins/ofagent/__init__.py delete mode 100644 neutron/plugins/ofagent/agent/__init__.py delete mode 100644 neutron/plugins/ofagent/agent/ofa_neutron_agent.py delete mode 100644 neutron/plugins/ofagent/common/__init__.py delete mode 100644 neutron/plugins/ofagent/common/config.py delete mode 100644 neutron/plugins/oneconvergence/README delete mode 100644 neutron/plugins/oneconvergence/__init__.py delete mode 100644 neutron/plugins/oneconvergence/agent/__init__.py delete mode 100644 neutron/plugins/oneconvergence/agent/nvsd_neutron_agent.py delete mode 100644 neutron/plugins/oneconvergence/lib/__init__.py delete mode 100644 neutron/plugins/oneconvergence/lib/config.py delete mode 100644 neutron/plugins/oneconvergence/lib/exception.py delete mode 100644 neutron/plugins/oneconvergence/lib/nvsd_db.py delete mode 100644 neutron/plugins/oneconvergence/lib/nvsdlib.py delete mode 100644 neutron/plugins/oneconvergence/lib/plugin_helper.py delete mode 100644 neutron/plugins/oneconvergence/plugin.py delete mode 100644 neutron/plugins/openvswitch/README delete mode 100644 neutron/plugins/openvswitch/__init__.py delete mode 100644 neutron/plugins/openvswitch/agent/__init__.py delete mode 100644 neutron/plugins/openvswitch/agent/ovs_neutron_agent.py delete mode 100644 neutron/plugins/openvswitch/agent/xenapi/README delete mode 100755 neutron/plugins/openvswitch/agent/xenapi/contrib/build-rpm.sh delete mode 100644 neutron/plugins/openvswitch/agent/xenapi/contrib/rpmbuild/SPECS/openstack-quantum-xen-plugins.spec delete mode 100644 neutron/plugins/openvswitch/agent/xenapi/etc/xapi.d/plugins/netwrap delete mode 100644 neutron/plugins/openvswitch/common/__init__.py delete mode 100644 neutron/plugins/openvswitch/common/config.py delete mode 100644 neutron/plugins/openvswitch/common/constants.py delete mode 100644 neutron/plugins/openvswitch/ovs_db_v2.py delete mode 100644 neutron/plugins/openvswitch/ovs_models_v2.py delete mode 100644 neutron/plugins/openvswitch/ovs_neutron_plugin.py delete mode 100644 neutron/plugins/plumgrid/README delete mode 100644 neutron/plugins/plumgrid/__init__.py delete mode 100644 neutron/plugins/plumgrid/common/__init__.py delete mode 100644 neutron/plugins/plumgrid/common/exceptions.py delete mode 100644 neutron/plugins/plumgrid/drivers/__init__.py delete mode 100644 neutron/plugins/plumgrid/drivers/fake_plumlib.py delete mode 100644 neutron/plugins/plumgrid/drivers/plumlib.py delete mode 100644 neutron/plugins/plumgrid/plumgrid_plugin/__init__.py delete mode 100644 neutron/plugins/plumgrid/plumgrid_plugin/plugin_ver.py delete mode 100644 neutron/plugins/plumgrid/plumgrid_plugin/plumgrid_plugin.py delete mode 100644 neutron/plugins/ryu/README delete mode 100644 neutron/plugins/ryu/__init__.py delete mode 100644 neutron/plugins/ryu/agent/__init__.py delete mode 100755 neutron/plugins/ryu/agent/ryu_neutron_agent.py delete mode 100644 neutron/plugins/ryu/common/__init__.py delete mode 100644 neutron/plugins/ryu/common/config.py delete mode 100644 neutron/plugins/ryu/db/__init__.py delete mode 100644 neutron/plugins/ryu/db/api_v2.py delete mode 100644 neutron/plugins/ryu/db/models_v2.py delete mode 100644 neutron/plugins/ryu/ryu_neutron_plugin.py delete mode 100644 neutron/plugins/vmware/__init__.py delete mode 100644 neutron/plugins/vmware/api_client/__init__.py delete mode 100644 neutron/plugins/vmware/api_client/base.py delete mode 100644 neutron/plugins/vmware/api_client/client.py delete mode 100644 neutron/plugins/vmware/api_client/eventlet_client.py delete mode 100644 neutron/plugins/vmware/api_client/eventlet_request.py delete mode 100644 neutron/plugins/vmware/api_client/exception.py delete mode 100644 neutron/plugins/vmware/api_client/request.py delete mode 100644 neutron/plugins/vmware/api_client/version.py delete mode 100644 neutron/plugins/vmware/check_nsx_config.py delete mode 100644 neutron/plugins/vmware/common/__init__.py delete mode 100644 neutron/plugins/vmware/common/config.py delete mode 100644 neutron/plugins/vmware/common/exceptions.py delete mode 100644 neutron/plugins/vmware/common/nsx_utils.py delete mode 100644 neutron/plugins/vmware/common/securitygroups.py delete mode 100644 neutron/plugins/vmware/common/sync.py delete mode 100644 neutron/plugins/vmware/common/utils.py delete mode 100644 neutron/plugins/vmware/dbexts/__init__.py delete mode 100644 neutron/plugins/vmware/dbexts/db.py delete mode 100644 neutron/plugins/vmware/dbexts/distributedrouter.py delete mode 100644 neutron/plugins/vmware/dbexts/lsn_db.py delete mode 100644 neutron/plugins/vmware/dbexts/maclearning.py delete mode 100644 neutron/plugins/vmware/dbexts/models.py delete mode 100644 neutron/plugins/vmware/dbexts/networkgw_db.py delete mode 100644 neutron/plugins/vmware/dbexts/nsxrouter.py delete mode 100644 neutron/plugins/vmware/dbexts/qos_db.py delete mode 100644 neutron/plugins/vmware/dbexts/servicerouter.py delete mode 100644 neutron/plugins/vmware/dbexts/vcns_db.py delete mode 100644 neutron/plugins/vmware/dbexts/vcns_models.py delete mode 100644 neutron/plugins/vmware/dhcp_meta/__init__.py delete mode 100644 neutron/plugins/vmware/dhcp_meta/combined.py delete mode 100644 neutron/plugins/vmware/dhcp_meta/constants.py delete mode 100644 neutron/plugins/vmware/dhcp_meta/lsnmanager.py delete mode 100644 neutron/plugins/vmware/dhcp_meta/migration.py delete mode 100644 neutron/plugins/vmware/dhcp_meta/nsx.py delete mode 100644 neutron/plugins/vmware/dhcp_meta/rpc.py delete mode 100644 neutron/plugins/vmware/dhcpmeta_modes.py delete mode 100644 neutron/plugins/vmware/extensions/__init__.py delete mode 100644 neutron/plugins/vmware/extensions/distributedrouter.py delete mode 100644 neutron/plugins/vmware/extensions/lsn.py delete mode 100644 neutron/plugins/vmware/extensions/maclearning.py delete mode 100644 neutron/plugins/vmware/extensions/networkgw.py delete mode 100644 neutron/plugins/vmware/extensions/nvp_qos.py delete mode 100644 neutron/plugins/vmware/extensions/qos.py delete mode 100644 neutron/plugins/vmware/extensions/servicerouter.py delete mode 100644 neutron/plugins/vmware/nsx_cluster.py delete mode 100644 neutron/plugins/vmware/nsxlib/__init__.py delete mode 100644 neutron/plugins/vmware/nsxlib/l2gateway.py delete mode 100644 neutron/plugins/vmware/nsxlib/lsn.py delete mode 100644 neutron/plugins/vmware/nsxlib/queue.py delete mode 100644 neutron/plugins/vmware/nsxlib/router.py delete mode 100644 neutron/plugins/vmware/nsxlib/secgroup.py delete mode 100644 neutron/plugins/vmware/nsxlib/switch.py delete mode 100644 neutron/plugins/vmware/nsxlib/versioning.py delete mode 100644 neutron/plugins/vmware/plugin.py delete mode 100644 neutron/plugins/vmware/plugins/__init__.py delete mode 100644 neutron/plugins/vmware/plugins/base.py delete mode 100644 neutron/plugins/vmware/plugins/service.py delete mode 100644 neutron/plugins/vmware/shell/__init__.py delete mode 100644 neutron/plugins/vmware/shell/commands.py delete mode 100644 neutron/plugins/vmware/vshield/__init__.py delete mode 100644 neutron/plugins/vmware/vshield/common/VcnsApiClient.py delete mode 100644 neutron/plugins/vmware/vshield/common/__init__.py delete mode 100644 neutron/plugins/vmware/vshield/common/constants.py delete mode 100644 neutron/plugins/vmware/vshield/common/exceptions.py delete mode 100644 neutron/plugins/vmware/vshield/edge_appliance_driver.py delete mode 100644 neutron/plugins/vmware/vshield/edge_firewall_driver.py delete mode 100644 neutron/plugins/vmware/vshield/edge_ipsecvpn_driver.py delete mode 100644 neutron/plugins/vmware/vshield/edge_loadbalancer_driver.py delete mode 100644 neutron/plugins/vmware/vshield/tasks/__init__.py delete mode 100644 neutron/plugins/vmware/vshield/tasks/constants.py delete mode 100644 neutron/plugins/vmware/vshield/tasks/tasks.py delete mode 100644 neutron/plugins/vmware/vshield/vcns.py delete mode 100644 neutron/plugins/vmware/vshield/vcns_driver.py diff --git a/neutron/plugins/bigswitch/README b/neutron/plugins/bigswitch/README deleted file mode 100644 index 43f157d12..000000000 --- a/neutron/plugins/bigswitch/README +++ /dev/null @@ -1,14 +0,0 @@ -# Neuron REST Proxy Plug-in for Big Switch and FloodLight Controllers - -This module provides a generic neutron plugin 'NeutronRestProxy' that -translates neutron function calls to authenticated REST requests (JSON supported) -to a set of redundant external network controllers. - -It also keeps a local persistent store of neutron state that has been -setup using that API. - -Currently the FloodLight Openflow Controller or the Big Switch Networks Controller -can be configured as external network controllers for this plugin. - -For more details on this plugin, please refer to the following link: -http://www.openflowhub.org/display/floodlightcontroller/Neutron+REST+Proxy+Plugin diff --git a/neutron/plugins/bigswitch/__init__.py b/neutron/plugins/bigswitch/__init__.py deleted file mode 100644 index 2a2421616..000000000 --- a/neutron/plugins/bigswitch/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012 Big Switch Networks, Inc. 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. -# diff --git a/neutron/plugins/bigswitch/agent/__init__.py b/neutron/plugins/bigswitch/agent/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/neutron/plugins/bigswitch/agent/restproxy_agent.py b/neutron/plugins/bigswitch/agent/restproxy_agent.py deleted file mode 100644 index 97aa7d0e3..000000000 --- a/neutron/plugins/bigswitch/agent/restproxy_agent.py +++ /dev/null @@ -1,181 +0,0 @@ -# Copyright 2014 Big Switch Networks, Inc. -# All Rights Reserved. -# -# Copyright 2011 VMware, Inc. -# 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: Kevin Benton, kevin.benton@bigswitch.com - -import sys -import time - -import eventlet -eventlet.monkey_patch() - -from oslo.config import cfg - -from neutron.agent.linux import ovs_lib -from neutron.agent.linux import utils -from neutron.agent import rpc as agent_rpc -from neutron.agent import securitygroups_rpc as sg_rpc -from neutron.common import config -from neutron.common import rpc_compat -from neutron.common import topics -from neutron import context as q_context -from neutron.extensions import securitygroup as ext_sg -from neutron.openstack.common import excutils -from neutron.openstack.common import log -from neutron.plugins.bigswitch import config as pl_config - -LOG = log.getLogger(__name__) - - -class IVSBridge(ovs_lib.OVSBridge): - ''' - This class does not provide parity with OVS using IVS. - It's only the bare minimum necessary to use IVS with this agent. - ''' - def run_vsctl(self, args, check_error=False): - full_args = ["ivs-ctl"] + args - try: - return utils.execute(full_args, root_helper=self.root_helper) - except Exception as e: - with excutils.save_and_reraise_exception() as ctxt: - LOG.error(_("Unable to execute %(cmd)s. " - "Exception: %(exception)s"), - {'cmd': full_args, 'exception': e}) - if not check_error: - ctxt.reraise = False - - def get_vif_port_set(self): - port_names = self.get_port_name_list() - edge_ports = set(port_names) - return edge_ports - - def get_vif_port_by_id(self, port_id): - # IVS in nova uses hybrid method with last 14 chars of UUID - name = 'qvo%s' % port_id[:14] - if name in self.get_vif_port_set(): - return name - return False - - -class PluginApi(agent_rpc.PluginApi, - sg_rpc.SecurityGroupServerRpcApiMixin): - pass - - -class SecurityGroupAgent(sg_rpc.SecurityGroupAgentRpcMixin): - def __init__(self, context, plugin_rpc, root_helper): - self.context = context - self.plugin_rpc = plugin_rpc - self.root_helper = root_helper - self.init_firewall() - - -class RestProxyAgent(rpc_compat.RpcCallback, - sg_rpc.SecurityGroupAgentRpcCallbackMixin): - - RPC_API_VERSION = '1.1' - - def __init__(self, integ_br, polling_interval, root_helper, vs='ovs'): - super(RestProxyAgent, self).__init__() - self.polling_interval = polling_interval - self._setup_rpc() - self.sg_agent = SecurityGroupAgent(self.context, - self.plugin_rpc, - root_helper) - if vs == 'ivs': - self.int_br = IVSBridge(integ_br, root_helper) - else: - self.int_br = ovs_lib.OVSBridge(integ_br, root_helper) - - def _setup_rpc(self): - self.topic = topics.AGENT - self.plugin_rpc = PluginApi(topics.PLUGIN) - self.context = q_context.get_admin_context_without_session() - self.endpoints = [self] - consumers = [[topics.PORT, topics.UPDATE], - [topics.SECURITY_GROUP, topics.UPDATE]] - self.connection = agent_rpc.create_consumers(self.endpoints, - self.topic, - consumers) - - def port_update(self, context, **kwargs): - LOG.debug(_("Port update received")) - port = kwargs.get('port') - vif_port = self.int_br.get_vif_port_by_id(port['id']) - if not vif_port: - LOG.debug(_("Port %s is not present on this host."), port['id']) - return - - LOG.debug(_("Port %s found. Refreshing firewall."), port['id']) - if ext_sg.SECURITYGROUPS in port: - self.sg_agent.refresh_firewall() - - def _update_ports(self, registered_ports): - ports = self.int_br.get_vif_port_set() - if ports == registered_ports: - return - added = ports - registered_ports - removed = registered_ports - ports - return {'current': ports, - 'added': added, - 'removed': removed} - - def _process_devices_filter(self, port_info): - if 'added' in port_info: - self.sg_agent.prepare_devices_filter(port_info['added']) - if 'removed' in port_info: - self.sg_agent.remove_devices_filter(port_info['removed']) - - def daemon_loop(self): - ports = set() - - while True: - start = time.time() - try: - port_info = self._update_ports(ports) - if port_info: - LOG.debug(_("Agent loop has new device")) - self._process_devices_filter(port_info) - ports = port_info['current'] - except Exception: - LOG.exception(_("Error in agent event loop")) - - elapsed = max(time.time() - start, 0) - if (elapsed < self.polling_interval): - time.sleep(self.polling_interval - elapsed) - else: - LOG.debug(_("Loop iteration exceeded interval " - "(%(polling_interval)s vs. %(elapsed)s)!"), - {'polling_interval': self.polling_interval, - 'elapsed': elapsed}) - - -def main(): - config.init(sys.argv[1:]) - config.setup_logging(cfg.CONF) - pl_config.register_config() - - integ_br = cfg.CONF.RESTPROXYAGENT.integration_bridge - polling_interval = cfg.CONF.RESTPROXYAGENT.polling_interval - root_helper = cfg.CONF.AGENT.root_helper - bsnagent = RestProxyAgent(integ_br, polling_interval, root_helper, - cfg.CONF.RESTPROXYAGENT.virtual_switch_type) - bsnagent.daemon_loop() - sys.exit(0) - -if __name__ == "__main__": - main() diff --git a/neutron/plugins/bigswitch/config.py b/neutron/plugins/bigswitch/config.py deleted file mode 100644 index 4646319c9..000000000 --- a/neutron/plugins/bigswitch/config.py +++ /dev/null @@ -1,123 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2014 Big Switch Networks, Inc. -# 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: Mandeep Dhami, Big Switch Networks, Inc. -# @author: Sumit Naiksatam, sumitnaiksatam@gmail.com, Big Switch Networks, Inc. -# @author: Kevin Benton, Big Switch Networks, Inc. - -""" -This module manages configuration options -""" - -from oslo.config import cfg - -from neutron.agent.common import config as agconfig -from neutron.common import utils -from neutron.extensions import portbindings - -restproxy_opts = [ - cfg.ListOpt('servers', default=['localhost:8800'], - help=_("A comma separated list of Big Switch or Floodlight " - "servers and port numbers. The plugin proxies the " - "requests to the Big Switch/Floodlight server, " - "which performs the networking configuration. Only one" - "server is needed per deployment, but you may wish to" - "deploy multiple servers to support failover.")), - cfg.StrOpt('server_auth', secret=True, - help=_("The username and password for authenticating against " - " the Big Switch or Floodlight controller.")), - cfg.BoolOpt('server_ssl', default=True, - help=_("If True, Use SSL when connecting to the Big Switch or " - "Floodlight controller.")), - cfg.BoolOpt('ssl_sticky', default=True, - help=_("Trust and store the first certificate received for " - "each controller address and use it to validate future " - "connections to that address.")), - cfg.BoolOpt('no_ssl_validation', default=False, - help=_("Disables SSL certificate validation for controllers")), - cfg.BoolOpt('cache_connections', default=True, - help=_("Re-use HTTP/HTTPS connections to the controller.")), - cfg.StrOpt('ssl_cert_directory', - default='/etc/neutron/plugins/bigswitch/ssl', - help=_("Directory containing ca_certs and host_certs " - "certificate directories.")), - cfg.BoolOpt('sync_data', default=False, - help=_("Sync data on connect")), - cfg.BoolOpt('auto_sync_on_failure', default=True, - help=_("If neutron fails to create a resource because " - "the backend controller doesn't know of a dependency, " - "the plugin automatically triggers a full data " - "synchronization to the controller.")), - cfg.IntOpt('consistency_interval', default=60, - help=_("Time between verifications that the backend controller " - "database is consistent with Neutron. (0 to disable)")), - cfg.IntOpt('server_timeout', default=10, - help=_("Maximum number of seconds to wait for proxy request " - "to connect and complete.")), - cfg.IntOpt('thread_pool_size', default=4, - help=_("Maximum number of threads to spawn to handle large " - "volumes of port creations.")), - cfg.StrOpt('neutron_id', default='neutron-' + utils.get_hostname(), - deprecated_name='quantum_id', - help=_("User defined identifier for this Neutron deployment")), - cfg.BoolOpt('add_meta_server_route', default=True, - help=_("Flag to decide if a route to the metadata server " - "should be injected into the VM")), -] -router_opts = [ - cfg.MultiStrOpt('tenant_default_router_rule', default=['*:any:any:permit'], - help=_("The default router rules installed in new tenant " - "routers. Repeat the config option for each rule. " - "Format is :::" - " Use an * to specify default for all tenants.")), - cfg.IntOpt('max_router_rules', default=200, - help=_("Maximum number of router rules")), -] -nova_opts = [ - cfg.StrOpt('vif_type', default='ovs', - help=_("Virtual interface type to configure on " - "Nova compute nodes")), -] - -# Each VIF Type can have a list of nova host IDs that are fixed to that type -for i in portbindings.VIF_TYPES: - opt = cfg.ListOpt('node_override_vif_' + i, default=[], - help=_("Nova compute nodes to manually set VIF " - "type to %s") % i) - nova_opts.append(opt) - -# Add the vif types for reference later -nova_opts.append(cfg.ListOpt('vif_types', - default=portbindings.VIF_TYPES, - help=_('List of allowed vif_type values.'))) - -agent_opts = [ - cfg.StrOpt('integration_bridge', default='br-int', - help=_('Name of integration bridge on compute ' - 'nodes used for security group insertion.')), - cfg.IntOpt('polling_interval', default=5, - help=_('Seconds between agent checks for port changes')), - cfg.StrOpt('virtual_switch_type', default='ovs', - help=_('Virtual switch type.')) -] - - -def register_config(): - cfg.CONF.register_opts(restproxy_opts, "RESTPROXY") - cfg.CONF.register_opts(router_opts, "ROUTER") - cfg.CONF.register_opts(nova_opts, "NOVA") - cfg.CONF.register_opts(agent_opts, "RESTPROXYAGENT") - agconfig.register_root_helper(cfg.CONF) diff --git a/neutron/plugins/bigswitch/db/__init__.py b/neutron/plugins/bigswitch/db/__init__.py deleted file mode 100644 index c05daecf8..000000000 --- a/neutron/plugins/bigswitch/db/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Big Switch Networks, Inc. -# 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: Kevin Benton, Big Switch Networks, Inc. diff --git a/neutron/plugins/bigswitch/db/consistency_db.py b/neutron/plugins/bigswitch/db/consistency_db.py deleted file mode 100644 index cd89a2690..000000000 --- a/neutron/plugins/bigswitch/db/consistency_db.py +++ /dev/null @@ -1,56 +0,0 @@ -# Copyright 2014, Big Switch Networks -# 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. -import sqlalchemy as sa - -from neutron.db import api as db -from neutron.db import model_base -from neutron.openstack.common import log as logging - -LOG = logging.getLogger(__name__) - -''' -A simple table to store the latest consistency hash -received from a server in case neutron gets restarted. -''' - - -class ConsistencyHash(model_base.BASEV2): - ''' - For now we only support one global state so the - hash_id will always be '1' - ''' - __tablename__ = 'consistencyhashes' - hash_id = sa.Column(sa.String(255), - primary_key=True) - hash = sa.Column(sa.String(255), nullable=False) - - -def get_consistency_hash(hash_id='1'): - session = db.get_session() - with session.begin(subtransactions=True): - query = session.query(ConsistencyHash) - res = query.filter_by(hash_id=hash_id).first() - if not res: - return False - return res.hash - - -def put_consistency_hash(hash, hash_id='1'): - session = db.get_session() - with session.begin(subtransactions=True): - conhash = ConsistencyHash(hash_id=hash_id, hash=hash) - session.merge(conhash) - LOG.debug(_("Consistency hash for group %(hash_id)s updated " - "to %(hash)s"), {'hash_id': hash_id, 'hash': hash}) diff --git a/neutron/plugins/bigswitch/db/porttracker_db.py b/neutron/plugins/bigswitch/db/porttracker_db.py deleted file mode 100644 index 7966c7c7d..000000000 --- a/neutron/plugins/bigswitch/db/porttracker_db.py +++ /dev/null @@ -1,53 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2013, Big Switch Networks -# 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 neutron.api.v2 import attributes -from neutron.openstack.common import log as logging - -LOG = logging.getLogger(__name__) - - -def get_port_hostid(context, port_id): - # REVISIT(kevinbenton): this is a workaround to avoid portbindings_db - # relational table generation until one of the functions is called. - from neutron.db import portbindings_db - with context.session.begin(subtransactions=True): - query = context.session.query(portbindings_db.PortBindingPort) - res = query.filter_by(port_id=port_id).first() - if not res: - return False - return res.host - - -def put_port_hostid(context, port_id, host): - # REVISIT(kevinbenton): this is a workaround to avoid portbindings_db - # relational table generation until one of the functions is called. - from neutron.db import portbindings_db - if not attributes.is_attr_set(host): - LOG.warning(_("No host_id in port request to track port location.")) - return - if port_id == '': - LOG.warning(_("Received an empty port ID for host_id '%s'"), host) - return - if host == '': - LOG.debug(_("Received an empty host_id for port '%s'"), port_id) - return - LOG.debug(_("Logging port %(port)s on host_id %(host)s"), - {'port': port_id, 'host': host}) - with context.session.begin(subtransactions=True): - location = portbindings_db.PortBindingPort(port_id=port_id, host=host) - context.session.merge(location) diff --git a/neutron/plugins/bigswitch/extensions/__init__.py b/neutron/plugins/bigswitch/extensions/__init__.py deleted file mode 100644 index c05daecf8..000000000 --- a/neutron/plugins/bigswitch/extensions/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Big Switch Networks, Inc. -# 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: Kevin Benton, Big Switch Networks, Inc. diff --git a/neutron/plugins/bigswitch/extensions/routerrule.py b/neutron/plugins/bigswitch/extensions/routerrule.py deleted file mode 100644 index 2563d113d..000000000 --- a/neutron/plugins/bigswitch/extensions/routerrule.py +++ /dev/null @@ -1,144 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Big Switch Networks, Inc. -# 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: Kevin Benton, Big Switch Networks, Inc. - -from neutron.api.v2 import attributes as attr -from neutron.common import exceptions as qexception -from neutron.openstack.common import log as logging - - -LOG = logging.getLogger(__name__) - - -# Router Rules Exceptions -class InvalidRouterRules(qexception.InvalidInput): - message = _("Invalid format for router rules: %(rule)s, %(reason)s") - - -class RulesExhausted(qexception.BadRequest): - message = _("Unable to complete rules update for %(router_id)s. " - "The number of rules exceeds the maximum %(quota)s.") - - -def convert_to_valid_router_rules(data): - """ - Validates and converts router rules to the appropriate data structure - Example argument = [{'source': 'any', 'destination': 'any', - 'action':'deny'}, - {'source': '1.1.1.1/32', 'destination': 'external', - 'action':'permit', - 'nexthops': ['1.1.1.254', '1.1.1.253']} - ] - """ - V4ANY = '0.0.0.0/0' - CIDRALL = ['any', 'external'] - if not isinstance(data, list): - emsg = _("Invalid data format for router rule: '%s'") % data - LOG.debug(emsg) - raise qexception.InvalidInput(error_message=emsg) - _validate_uniquerules(data) - rules = [] - expected_keys = ['source', 'destination', 'action'] - for rule in data: - rule['nexthops'] = rule.get('nexthops', []) - if not isinstance(rule['nexthops'], list): - rule['nexthops'] = rule['nexthops'].split('+') - - src = V4ANY if rule['source'] in CIDRALL else rule['source'] - dst = V4ANY if rule['destination'] in CIDRALL else rule['destination'] - - errors = [attr._verify_dict_keys(expected_keys, rule, False), - attr._validate_subnet(dst), - attr._validate_subnet(src), - _validate_nexthops(rule['nexthops']), - _validate_action(rule['action'])] - errors = [m for m in errors if m] - if errors: - LOG.debug(errors) - raise qexception.InvalidInput(error_message=errors) - rules.append(rule) - return rules - - -def _validate_nexthops(nexthops): - seen = [] - for ip in nexthops: - msg = attr._validate_ip_address(ip) - if ip in seen: - msg = _("Duplicate nexthop in rule '%s'") % ip - seen.append(ip) - if msg: - return msg - - -def _validate_action(action): - if action not in ['permit', 'deny']: - return _("Action must be either permit or deny." - " '%s' was provided") % action - - -def _validate_uniquerules(rules): - pairs = [] - for r in rules: - if 'source' not in r or 'destination' not in r: - continue - pairs.append((r['source'], r['destination'])) - - if len(set(pairs)) != len(pairs): - error = _("Duplicate router rules (src,dst) found '%s'") % pairs - LOG.debug(error) - raise qexception.InvalidInput(error_message=error) - - -class Routerrule(object): - - @classmethod - def get_name(cls): - return "Neutron Router Rule" - - @classmethod - def get_alias(cls): - return "router_rules" - - @classmethod - def get_description(cls): - return "Router rule configuration for L3 router" - - @classmethod - def get_namespace(cls): - return "http://docs.openstack.org/ext/neutron/routerrules/api/v1.0" - - @classmethod - def get_updated(cls): - return "2013-05-23T10:00:00-00:00" - - def get_extended_resources(self, version): - if version == "2.0": - return EXTENDED_ATTRIBUTES_2_0 - else: - return {} - -# Attribute Map -EXTENDED_ATTRIBUTES_2_0 = { - 'routers': { - 'router_rules': {'allow_post': False, 'allow_put': True, - 'convert_to': convert_to_valid_router_rules, - 'is_visible': True, - 'default': attr.ATTR_NOT_SPECIFIED}, - } -} diff --git a/neutron/plugins/bigswitch/plugin.py b/neutron/plugins/bigswitch/plugin.py deleted file mode 100644 index c13c45b65..000000000 --- a/neutron/plugins/bigswitch/plugin.py +++ /dev/null @@ -1,1115 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2012 Big Switch Networks, Inc. -# 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: Mandeep Dhami, Big Switch Networks, Inc. -# @author: Sumit Naiksatam, sumitnaiksatam@gmail.com, Big Switch Networks, Inc. - -""" -Neutron REST Proxy Plug-in for Big Switch and FloodLight Controllers. - -NeutronRestProxy provides a generic neutron plugin that translates all plugin -function calls to equivalent authenticated REST calls to a set of redundant -external network controllers. It also keeps persistent store for all neutron -state to allow for re-sync of the external controller(s), if required. - -The local state on the plugin also allows for local response and fast-fail -semantics where it can be determined based on the local persistent store. - -Network controller specific code is decoupled from this plugin and expected -to reside on the controller itself (via the REST interface). - -This allows for: - - independent authentication and redundancy schemes between neutron and the - network controller - - independent upgrade/development cycles between neutron and the controller - as it limits the proxy code upgrade requirement to neutron release cycle - and the controller specific code upgrade requirement to controller code - - ability to sync the controller with neutron for independent recovery/reset - -External REST API used by proxy is the same API as defined for neutron (JSON -subset) with some additional parameters (gateway on network-create and macaddr -on port-attach) on an additional PUT to do a bulk dump of all persistent data. -""" - -import copy -import httplib -import re - -import eventlet -from oslo.config import cfg -from sqlalchemy.orm import exc as sqlexc - -from neutron.agent import securitygroups_rpc as sg_rpc -from neutron.api import extensions as neutron_extensions -from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api -from neutron.common import constants as const -from neutron.common import exceptions -from neutron.common import rpc_compat -from neutron.common import topics -from neutron.common import utils -from neutron import context as qcontext -from neutron.db import agents_db -from neutron.db import agentschedulers_db -from neutron.db import allowedaddresspairs_db as addr_pair_db -from neutron.db import api as db -from neutron.db import db_base_plugin_v2 -from neutron.db import dhcp_rpc_base -from neutron.db import external_net_db -from neutron.db import extradhcpopt_db -from neutron.db import l3_db -from neutron.db import models_v2 -from neutron.db import securitygroups_db as sg_db -from neutron.db import securitygroups_rpc_base as sg_rpc_base -from neutron.extensions import allowedaddresspairs as addr_pair -from neutron.extensions import external_net -from neutron.extensions import extra_dhcp_opt as edo_ext -from neutron.extensions import l3 -from neutron.extensions import portbindings -from neutron import manager -from neutron.openstack.common import excutils -from neutron.openstack.common import importutils -from neutron.openstack.common import log as logging -from neutron.plugins.bigswitch import config as pl_config -from neutron.plugins.bigswitch.db import porttracker_db -from neutron.plugins.bigswitch import extensions -from neutron.plugins.bigswitch import routerrule_db -from neutron.plugins.bigswitch import servermanager -from neutron.plugins.bigswitch import version - -LOG = logging.getLogger(__name__) - -SYNTAX_ERROR_MESSAGE = _('Syntax error in server config file, aborting plugin') -METADATA_SERVER_IP = '169.254.169.254' - - -class AgentNotifierApi(rpc_compat.RpcProxy, - sg_rpc.SecurityGroupAgentRpcApiMixin): - - BASE_RPC_API_VERSION = '1.1' - - def __init__(self, topic): - super(AgentNotifierApi, self).__init__( - topic=topic, default_version=self.BASE_RPC_API_VERSION) - self.topic_port_update = topics.get_topic_name( - topic, topics.PORT, topics.UPDATE) - - def port_update(self, context, port): - self.fanout_cast(context, - self.make_msg('port_update', - port=port), - topic=self.topic_port_update) - - -class RestProxyCallbacks(rpc_compat.RpcCallback, - sg_rpc_base.SecurityGroupServerRpcCallbackMixin, - dhcp_rpc_base.DhcpRpcCallbackMixin): - - RPC_API_VERSION = '1.1' - - def get_port_from_device(self, device): - port_id = re.sub(r"^tap", "", device) - port = self.get_port_and_sgs(port_id) - if port: - port['device'] = device - return port - - def get_port_and_sgs(self, port_id): - """Get port from database with security group info.""" - - LOG.debug(_("get_port_and_sgs() called for port_id %s"), port_id) - session = db.get_session() - sg_binding_port = sg_db.SecurityGroupPortBinding.port_id - - with session.begin(subtransactions=True): - query = session.query( - models_v2.Port, - sg_db.SecurityGroupPortBinding.security_group_id - ) - query = query.outerjoin(sg_db.SecurityGroupPortBinding, - models_v2.Port.id == sg_binding_port) - query = query.filter(models_v2.Port.id.startswith(port_id)) - port_and_sgs = query.all() - if not port_and_sgs: - return - port = port_and_sgs[0][0] - plugin = manager.NeutronManager.get_plugin() - port_dict = plugin._make_port_dict(port) - port_dict['security_groups'] = [ - sg_id for port_, sg_id in port_and_sgs if sg_id] - port_dict['security_group_rules'] = [] - port_dict['security_group_source_groups'] = [] - port_dict['fixed_ips'] = [ip['ip_address'] - for ip in port['fixed_ips']] - return port_dict - - -class NeutronRestProxyV2Base(db_base_plugin_v2.NeutronDbPluginV2, - external_net_db.External_net_db_mixin, - routerrule_db.RouterRule_db_mixin): - - supported_extension_aliases = ["binding"] - servers = None - - def _get_all_data(self, get_ports=True, get_floating_ips=True, - get_routers=True): - admin_context = qcontext.get_admin_context() - networks = [] - # this method is used by the ML2 driver so it can't directly invoke - # the self.get_(ports|networks) methods - plugin = manager.NeutronManager.get_plugin() - all_networks = plugin.get_networks(admin_context) or [] - for net in all_networks: - mapped_network = self._get_mapped_network_with_subnets(net) - flips_n_ports = mapped_network - if get_floating_ips: - flips_n_ports = self._get_network_with_floatingips( - mapped_network) - - if get_ports: - ports = [] - net_filter = {'network_id': [net.get('id')]} - net_ports = plugin.get_ports(admin_context, - filters=net_filter) or [] - for port in net_ports: - mapped_port = self._map_state_and_status(port) - mapped_port['attachment'] = { - 'id': port.get('device_id'), - 'mac': port.get('mac_address'), - } - mapped_port = self._extend_port_dict_binding(admin_context, - mapped_port) - ports.append(mapped_port) - flips_n_ports['ports'] = ports - - if flips_n_ports: - networks.append(flips_n_ports) - - data = {'networks': networks} - - if get_routers: - routers = [] - all_routers = self.get_routers(admin_context) or [] - for router in all_routers: - interfaces = [] - mapped_router = self._map_state_and_status(router) - router_filter = { - 'device_owner': [const.DEVICE_OWNER_ROUTER_INTF], - 'device_id': [router.get('id')] - } - router_ports = self.get_ports(admin_context, - filters=router_filter) or [] - for port in router_ports: - net_id = port.get('network_id') - subnet_id = port['fixed_ips'][0]['subnet_id'] - intf_details = self._get_router_intf_details(admin_context, - net_id, - subnet_id) - interfaces.append(intf_details) - mapped_router['interfaces'] = interfaces - - routers.append(mapped_router) - - data.update({'routers': routers}) - return data - - def _send_all_data(self, send_ports=True, send_floating_ips=True, - send_routers=True, timeout=None, - triggered_by_tenant=None): - """Pushes all data to network ctrl (networks/ports, ports/attachments). - - This gives the controller an option to re-sync it's persistent store - with neutron's current view of that data. - """ - data = self._get_all_data(send_ports, send_floating_ips, send_routers) - data['triggered_by_tenant'] = triggered_by_tenant - errstr = _("Unable to update remote topology: %s") - return self.servers.rest_action('PUT', servermanager.TOPOLOGY_PATH, - data, errstr, timeout=timeout) - - def _get_network_with_floatingips(self, network, context=None): - if context is None: - context = qcontext.get_admin_context() - - net_id = network['id'] - net_filter = {'floating_network_id': [net_id]} - fl_ips = self.get_floatingips(context, - filters=net_filter) or [] - network['floatingips'] = fl_ips - - return network - - def _get_all_subnets_json_for_network(self, net_id, context=None): - if context is None: - context = qcontext.get_admin_context() - # start a sub-transaction to avoid breaking parent transactions - with context.session.begin(subtransactions=True): - subnets = self._get_subnets_by_network(context, - net_id) - subnets_details = [] - if subnets: - for subnet in subnets: - subnet_dict = self._make_subnet_dict(subnet) - mapped_subnet = self._map_state_and_status(subnet_dict) - subnets_details.append(mapped_subnet) - - return subnets_details - - def _get_mapped_network_with_subnets(self, network, context=None): - # if context is not provided, admin context is used - if context is None: - context = qcontext.get_admin_context() - network = self._map_state_and_status(network) - subnets = self._get_all_subnets_json_for_network(network['id'], - context) - network['subnets'] = subnets - for subnet in (subnets or []): - if subnet['gateway_ip']: - # FIX: For backward compatibility with wire protocol - network['gateway'] = subnet['gateway_ip'] - break - else: - network['gateway'] = '' - network[external_net.EXTERNAL] = self._network_is_external( - context, network['id']) - # include ML2 segmentation types - network['segmentation_types'] = getattr(self, "segmentation_types", "") - return network - - def _send_create_network(self, network, context=None): - tenant_id = network['tenant_id'] - mapped_network = self._get_mapped_network_with_subnets(network, - context) - self.servers.rest_create_network(tenant_id, mapped_network) - - def _send_update_network(self, network, context=None): - net_id = network['id'] - tenant_id = network['tenant_id'] - mapped_network = self._get_mapped_network_with_subnets(network, - context) - net_fl_ips = self._get_network_with_floatingips(mapped_network, - context) - self.servers.rest_update_network(tenant_id, net_id, net_fl_ips) - - def _send_delete_network(self, network, context=None): - net_id = network['id'] - tenant_id = network['tenant_id'] - self.servers.rest_delete_network(tenant_id, net_id) - - def _map_state_and_status(self, resource): - resource = copy.copy(resource) - - resource['state'] = ('UP' if resource.pop('admin_state_up', - True) else 'DOWN') - resource.pop('status', None) - - return resource - - def _warn_on_state_status(self, resource): - if resource.get('admin_state_up', True) is False: - LOG.warning(_("Setting admin_state_up=False is not supported " - "in this plugin version. Ignoring setting for " - "resource: %s"), resource) - - if 'status' in resource: - if resource['status'] != const.NET_STATUS_ACTIVE: - LOG.warning(_("Operational status is internally set by the " - "plugin. Ignoring setting status=%s."), - resource['status']) - - def _get_router_intf_details(self, context, intf_id, subnet_id): - - # we will use the network id as interface's id - net_id = intf_id - network = self.get_network(context, net_id) - subnet = self.get_subnet(context, subnet_id) - mapped_network = self._get_mapped_network_with_subnets(network) - mapped_subnet = self._map_state_and_status(subnet) - - data = { - 'id': intf_id, - "network": mapped_network, - "subnet": mapped_subnet - } - - return data - - def _extend_port_dict_binding(self, context, port): - cfg_vif_type = cfg.CONF.NOVA.vif_type.lower() - if not cfg_vif_type in (portbindings.VIF_TYPE_OVS, - portbindings.VIF_TYPE_IVS): - LOG.warning(_("Unrecognized vif_type in configuration " - "[%s]. Defaulting to ovs."), - cfg_vif_type) - cfg_vif_type = portbindings.VIF_TYPE_OVS - # In ML2, the host_id is already populated - if portbindings.HOST_ID in port: - hostid = port[portbindings.HOST_ID] - else: - hostid = porttracker_db.get_port_hostid(context, port['id']) - if hostid: - port[portbindings.HOST_ID] = hostid - override = self._check_hostvif_override(hostid) - if override: - cfg_vif_type = override - port[portbindings.VIF_TYPE] = cfg_vif_type - - port[portbindings.VIF_DETAILS] = { - # TODO(rkukura): Replace with new VIF security details - portbindings.CAP_PORT_FILTER: - 'security-group' in self.supported_extension_aliases, - portbindings.OVS_HYBRID_PLUG: True - } - return port - - def _check_hostvif_override(self, hostid): - for v in cfg.CONF.NOVA.vif_types: - if hostid in getattr(cfg.CONF.NOVA, "node_override_vif_" + v, []): - return v - return False - - def _get_port_net_tenantid(self, context, port): - net = super(NeutronRestProxyV2Base, - self).get_network(context, port["network_id"]) - return net['tenant_id'] - - def async_port_create(self, tenant_id, net_id, port): - try: - self.servers.rest_create_port(tenant_id, net_id, port) - except servermanager.RemoteRestError as e: - # 404 should never be received on a port create unless - # there are inconsistencies between the data in neutron - # and the data in the backend. - # Run a sync to get it consistent. - if (cfg.CONF.RESTPROXY.auto_sync_on_failure and - e.status == httplib.NOT_FOUND and - servermanager.NXNETWORK in e.reason): - LOG.error(_("Iconsistency with backend controller " - "triggering full synchronization.")) - # args depend on if we are operating in ML2 driver - # or as the full plugin - topoargs = self.servers.get_topo_function_args - self._send_all_data( - send_ports=topoargs['get_ports'], - send_floating_ips=topoargs['get_floating_ips'], - send_routers=topoargs['get_routers'], - triggered_by_tenant=tenant_id - ) - # If the full sync worked, the port will be created - # on the controller so it can be safely marked as active - else: - # Any errors that don't result in a successful auto-sync - # require that the port be placed into the error state. - LOG.error( - _("NeutronRestProxyV2: Unable to create port: %s"), e) - try: - self._set_port_status(port['id'], const.PORT_STATUS_ERROR) - except exceptions.PortNotFound: - # If port is already gone from DB and there was an error - # creating on the backend, everything is already consistent - pass - return - new_status = (const.PORT_STATUS_ACTIVE if port['state'] == 'UP' - else const.PORT_STATUS_DOWN) - try: - self._set_port_status(port['id'], new_status) - except exceptions.PortNotFound: - # This port was deleted before the create made it to the controller - # so it now needs to be deleted since the normal delete request - # would have deleted an non-existent port. - self.servers.rest_delete_port(tenant_id, net_id, port['id']) - - # NOTE(kevinbenton): workaround for eventlet/mysql deadlock - @utils.synchronized('bsn-port-barrier') - def _set_port_status(self, port_id, status): - session = db.get_session() - try: - port = session.query(models_v2.Port).filter_by(id=port_id).one() - port['status'] = status - session.flush() - except sqlexc.NoResultFound: - raise exceptions.PortNotFound(port_id=port_id) - - -class NeutronRestProxyV2(NeutronRestProxyV2Base, - addr_pair_db.AllowedAddressPairsMixin, - extradhcpopt_db.ExtraDhcpOptMixin, - agentschedulers_db.DhcpAgentSchedulerDbMixin, - sg_rpc_base.SecurityGroupServerRpcMixin): - - _supported_extension_aliases = ["external-net", "router", "binding", - "router_rules", "extra_dhcp_opt", "quotas", - "dhcp_agent_scheduler", "agent", - "security-group", "allowed-address-pairs"] - - @property - def supported_extension_aliases(self): - if not hasattr(self, '_aliases'): - aliases = self._supported_extension_aliases[:] - sg_rpc.disable_security_group_extension_by_config(aliases) - self._aliases = aliases - return self._aliases - - def __init__(self): - super(NeutronRestProxyV2, self).__init__() - LOG.info(_('NeutronRestProxy: Starting plugin. Version=%s'), - version.version_string_with_vcs()) - pl_config.register_config() - self.evpool = eventlet.GreenPool(cfg.CONF.RESTPROXY.thread_pool_size) - - # Include the Big Switch Extensions path in the api_extensions - neutron_extensions.append_api_extensions_path(extensions.__path__) - - self.add_meta_server_route = cfg.CONF.RESTPROXY.add_meta_server_route - - # init network ctrl connections - self.servers = servermanager.ServerPool() - self.servers.get_topo_function = self._get_all_data - self.servers.get_topo_function_args = {'get_ports': True, - 'get_floating_ips': True, - 'get_routers': True} - - self.network_scheduler = importutils.import_object( - cfg.CONF.network_scheduler_driver - ) - - # setup rpc for security and DHCP agents - self._setup_rpc() - - if cfg.CONF.RESTPROXY.sync_data: - self._send_all_data() - - LOG.debug(_("NeutronRestProxyV2: initialization done")) - - def _setup_rpc(self): - self.conn = rpc_compat.create_connection(new=True) - self.topic = topics.PLUGIN - self.notifier = AgentNotifierApi(topics.AGENT) - # init dhcp agent support - self._dhcp_agent_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI() - self.agent_notifiers[const.AGENT_TYPE_DHCP] = ( - self._dhcp_agent_notifier - ) - self.endpoints = [RestProxyCallbacks(), - agents_db.AgentExtRpcCallback()] - self.conn.create_consumer(self.topic, self.endpoints, - fanout=False) - # Consume from all consumers in threads - self.conn.consume_in_threads() - - def create_network(self, context, network): - """Create a network. - - Network represents an L2 network segment which can have a set of - subnets and ports associated with it. - - :param context: neutron api request context - :param network: dictionary describing the network - - :returns: a sequence of mappings with the following signature: - { - "id": UUID representing the network. - "name": Human-readable name identifying the network. - "tenant_id": Owner of network. NOTE: only admin user can specify - a tenant_id other than its own. - "admin_state_up": Sets admin state of network. - if down, network does not forward packets. - "status": Indicates whether network is currently operational - (values are "ACTIVE", "DOWN", "BUILD", and "ERROR") - "subnets": Subnets associated with this network. - } - - :raises: RemoteRestError - """ - LOG.debug(_("NeutronRestProxyV2: create_network() called")) - - self._warn_on_state_status(network['network']) - - with context.session.begin(subtransactions=True): - self._ensure_default_security_group( - context, - network['network']["tenant_id"] - ) - # create network in DB - new_net = super(NeutronRestProxyV2, self).create_network(context, - network) - self._process_l3_create(context, new_net, network['network']) - # create network on the network controller - self._send_create_network(new_net, context) - - # return created network - return new_net - - def update_network(self, context, net_id, network): - """Updates the properties of a particular Virtual Network. - - :param context: neutron api request context - :param net_id: uuid of the network to update - :param network: dictionary describing the updates - - :returns: a sequence of mappings with the following signature: - { - "id": UUID representing the network. - "name": Human-readable name identifying the network. - "tenant_id": Owner of network. NOTE: only admin user can - specify a tenant_id other than its own. - "admin_state_up": Sets admin state of network. - if down, network does not forward packets. - "status": Indicates whether network is currently operational - (values are "ACTIVE", "DOWN", "BUILD", and "ERROR") - "subnets": Subnets associated with this network. - } - - :raises: exceptions.NetworkNotFound - :raises: RemoteRestError - """ - LOG.debug(_("NeutronRestProxyV2.update_network() called")) - - self._warn_on_state_status(network['network']) - - session = context.session - with session.begin(subtransactions=True): - new_net = super(NeutronRestProxyV2, self).update_network( - context, net_id, network) - self._process_l3_update(context, new_net, network['network']) - - # update network on network controller - self._send_update_network(new_net, context) - return new_net - - # NOTE(kevinbenton): workaround for eventlet/mysql deadlock - @utils.synchronized('bsn-port-barrier') - def delete_network(self, context, net_id): - """Delete a network. - :param context: neutron api request context - :param id: UUID representing the network to delete. - - :returns: None - - :raises: exceptions.NetworkInUse - :raises: exceptions.NetworkNotFound - :raises: RemoteRestError - """ - LOG.debug(_("NeutronRestProxyV2: delete_network() called")) - - # Validate args - orig_net = super(NeutronRestProxyV2, self).get_network(context, net_id) - with context.session.begin(subtransactions=True): - self._process_l3_delete(context, net_id) - ret_val = super(NeutronRestProxyV2, self).delete_network(context, - net_id) - self._send_delete_network(orig_net, context) - return ret_val - - def create_port(self, context, port): - """Create a port, which is a connection point of a device - (e.g., a VM NIC) to attach to a L2 Neutron network. - :param context: neutron api request context - :param port: dictionary describing the port - - :returns: - { - "id": uuid represeting the port. - "network_id": uuid of network. - "tenant_id": tenant_id - "mac_address": mac address to use on this port. - "admin_state_up": Sets admin state of port. if down, port - does not forward packets. - "status": dicates whether port is currently operational - (limit values to "ACTIVE", "DOWN", "BUILD", and "ERROR") - "fixed_ips": list of subnet ID"s and IP addresses to be used on - this port - "device_id": identifies the device (e.g., virtual server) using - this port. - } - - :raises: exceptions.NetworkNotFound - :raises: exceptions.StateInvalid - :raises: RemoteRestError - """ - LOG.debug(_("NeutronRestProxyV2: create_port() called")) - - # Update DB in new session so exceptions rollback changes - with context.session.begin(subtransactions=True): - self._ensure_default_security_group_on_port(context, port) - sgids = self._get_security_groups_on_port(context, port) - # non-router port status is set to pending. it is then updated - # after the async rest call completes. router ports are synchronous - if port['port']['device_owner'] == l3_db.DEVICE_OWNER_ROUTER_INTF: - port['port']['status'] = const.PORT_STATUS_ACTIVE - else: - port['port']['status'] = const.PORT_STATUS_BUILD - dhcp_opts = port['port'].get(edo_ext.EXTRADHCPOPTS, []) - new_port = super(NeutronRestProxyV2, self).create_port(context, - port) - self._process_port_create_security_group(context, new_port, sgids) - if (portbindings.HOST_ID in port['port'] - and 'id' in new_port): - host_id = port['port'][portbindings.HOST_ID] - porttracker_db.put_port_hostid(context, new_port['id'], - host_id) - new_port[addr_pair.ADDRESS_PAIRS] = ( - self._process_create_allowed_address_pairs( - context, new_port, - port['port'].get(addr_pair.ADDRESS_PAIRS))) - self._process_port_create_extra_dhcp_opts(context, new_port, - dhcp_opts) - new_port = self._extend_port_dict_binding(context, new_port) - net = super(NeutronRestProxyV2, - self).get_network(context, new_port["network_id"]) - if self.add_meta_server_route: - if new_port['device_owner'] == const.DEVICE_OWNER_DHCP: - destination = METADATA_SERVER_IP + '/32' - self._add_host_route(context, destination, new_port) - - # create on network ctrl - mapped_port = self._map_state_and_status(new_port) - # ports have to be created synchronously when creating a router - # port since adding router interfaces is a multi-call process - if mapped_port['device_owner'] == l3_db.DEVICE_OWNER_ROUTER_INTF: - self.servers.rest_create_port(net["tenant_id"], - new_port["network_id"], - mapped_port) - else: - self.evpool.spawn_n(self.async_port_create, net["tenant_id"], - new_port["network_id"], mapped_port) - self.notify_security_groups_member_updated(context, new_port) - return new_port - - def get_port(self, context, id, fields=None): - with context.session.begin(subtransactions=True): - port = super(NeutronRestProxyV2, self).get_port(context, id, - fields) - self._extend_port_dict_binding(context, port) - return self._fields(port, fields) - - def get_ports(self, context, filters=None, fields=None): - with context.session.begin(subtransactions=True): - ports = super(NeutronRestProxyV2, self).get_ports(context, filters, - fields) - for port in ports: - self._extend_port_dict_binding(context, port) - return [self._fields(port, fields) for port in ports] - - def update_port(self, context, port_id, port): - """Update values of a port. - - :param context: neutron api request context - :param id: UUID representing the port to update. - :param port: dictionary with keys indicating fields to update. - - :returns: a mapping sequence with the following signature: - { - "id": uuid represeting the port. - "network_id": uuid of network. - "tenant_id": tenant_id - "mac_address": mac address to use on this port. - "admin_state_up": sets admin state of port. if down, port - does not forward packets. - "status": dicates whether port is currently operational - (limit values to "ACTIVE", "DOWN", "BUILD", and "ERROR") - "fixed_ips": list of subnet ID's and IP addresses to be used on - this port - "device_id": identifies the device (e.g., virtual server) using - this port. - } - - :raises: exceptions.StateInvalid - :raises: exceptions.PortNotFound - :raises: RemoteRestError - """ - LOG.debug(_("NeutronRestProxyV2: update_port() called")) - - self._warn_on_state_status(port['port']) - - # Validate Args - orig_port = super(NeutronRestProxyV2, self).get_port(context, port_id) - with context.session.begin(subtransactions=True): - # Update DB - new_port = super(NeutronRestProxyV2, - self).update_port(context, port_id, port) - ctrl_update_required = False - if addr_pair.ADDRESS_PAIRS in port['port']: - ctrl_update_required |= ( - self.update_address_pairs_on_port(context, port_id, port, - orig_port, new_port)) - self._update_extra_dhcp_opts_on_port(context, port_id, port, - new_port) - old_host_id = porttracker_db.get_port_hostid(context, - orig_port['id']) - if (portbindings.HOST_ID in port['port'] - and 'id' in new_port): - host_id = port['port'][portbindings.HOST_ID] - porttracker_db.put_port_hostid(context, new_port['id'], - host_id) - if old_host_id != host_id: - ctrl_update_required = True - - if (new_port.get("device_id") != orig_port.get("device_id") and - orig_port.get("device_id")): - ctrl_update_required = True - - if ctrl_update_required: - # tenant_id must come from network in case network is shared - net_tenant_id = self._get_port_net_tenantid(context, new_port) - new_port = self._extend_port_dict_binding(context, new_port) - mapped_port = self._map_state_and_status(new_port) - self.servers.rest_update_port(net_tenant_id, - new_port["network_id"], - mapped_port) - agent_update_required = self.update_security_group_on_port( - context, port_id, port, orig_port, new_port) - agent_update_required |= self.is_security_group_member_updated( - context, orig_port, new_port) - - # return new_port - return new_port - - # NOTE(kevinbenton): workaround for eventlet/mysql deadlock - @utils.synchronized('bsn-port-barrier') - def delete_port(self, context, port_id, l3_port_check=True): - """Delete a port. - :param context: neutron api request context - :param id: UUID representing the port to delete. - - :raises: exceptions.PortInUse - :raises: exceptions.PortNotFound - :raises: exceptions.NetworkNotFound - :raises: RemoteRestError - """ - LOG.debug(_("NeutronRestProxyV2: delete_port() called")) - - # if needed, check to see if this is a port owned by - # and l3-router. If so, we should prevent deletion. - if l3_port_check: - self.prevent_l3_port_deletion(context, port_id) - with context.session.begin(subtransactions=True): - self.disassociate_floatingips(context, port_id) - self._delete_port_security_group_bindings(context, port_id) - port = super(NeutronRestProxyV2, self).get_port(context, port_id) - # Tenant ID must come from network in case the network is shared - tenid = self._get_port_net_tenantid(context, port) - self._delete_port(context, port_id) - self.servers.rest_delete_port(tenid, port['network_id'], port_id) - - def create_subnet(self, context, subnet): - LOG.debug(_("NeutronRestProxyV2: create_subnet() called")) - - self._warn_on_state_status(subnet['subnet']) - - with context.session.begin(subtransactions=True): - # create subnet in DB - new_subnet = super(NeutronRestProxyV2, - self).create_subnet(context, subnet) - net_id = new_subnet['network_id'] - orig_net = super(NeutronRestProxyV2, - self).get_network(context, net_id) - # update network on network controller - self._send_update_network(orig_net, context) - return new_subnet - - def update_subnet(self, context, id, subnet): - LOG.debug(_("NeutronRestProxyV2: update_subnet() called")) - - self._warn_on_state_status(subnet['subnet']) - - with context.session.begin(subtransactions=True): - # update subnet in DB - new_subnet = super(NeutronRestProxyV2, - self).update_subnet(context, id, subnet) - net_id = new_subnet['network_id'] - orig_net = super(NeutronRestProxyV2, - self).get_network(context, net_id) - # update network on network controller - self._send_update_network(orig_net, context) - return new_subnet - - # NOTE(kevinbenton): workaround for eventlet/mysql deadlock - @utils.synchronized('bsn-port-barrier') - def delete_subnet(self, context, id): - LOG.debug(_("NeutronRestProxyV2: delete_subnet() called")) - orig_subnet = super(NeutronRestProxyV2, self).get_subnet(context, id) - net_id = orig_subnet['network_id'] - with context.session.begin(subtransactions=True): - # delete subnet in DB - super(NeutronRestProxyV2, self).delete_subnet(context, id) - orig_net = super(NeutronRestProxyV2, self).get_network(context, - net_id) - # update network on network controller - exception will rollback - self._send_update_network(orig_net, context) - - def _get_tenant_default_router_rules(self, tenant): - rules = cfg.CONF.ROUTER.tenant_default_router_rule - defaultset = [] - tenantset = [] - for rule in rules: - items = rule.split(':') - if len(items) == 5: - (tenantid, source, destination, action, nexthops) = items - elif len(items) == 4: - (tenantid, source, destination, action) = items - nexthops = '' - else: - continue - parsedrule = {'source': source, - 'destination': destination, 'action': action, - 'nexthops': nexthops.split(',')} - if parsedrule['nexthops'][0] == '': - parsedrule['nexthops'] = [] - if tenantid == '*': - defaultset.append(parsedrule) - if tenantid == tenant: - tenantset.append(parsedrule) - if tenantset: - return tenantset - return defaultset - - def create_router(self, context, router): - LOG.debug(_("NeutronRestProxyV2: create_router() called")) - - self._warn_on_state_status(router['router']) - - tenant_id = self._get_tenant_id_for_create(context, router["router"]) - - # set default router rules - rules = self._get_tenant_default_router_rules(tenant_id) - router['router']['router_rules'] = rules - - with context.session.begin(subtransactions=True): - # create router in DB - new_router = super(NeutronRestProxyV2, self).create_router(context, - router) - mapped_router = self._map_state_and_status(new_router) - self.servers.rest_create_router(tenant_id, mapped_router) - - # return created router - return new_router - - def update_router(self, context, router_id, router): - - LOG.debug(_("NeutronRestProxyV2.update_router() called")) - - self._warn_on_state_status(router['router']) - - orig_router = super(NeutronRestProxyV2, self).get_router(context, - router_id) - tenant_id = orig_router["tenant_id"] - with context.session.begin(subtransactions=True): - new_router = super(NeutronRestProxyV2, - self).update_router(context, router_id, router) - router = self._map_state_and_status(new_router) - - # update router on network controller - self.servers.rest_update_router(tenant_id, router, router_id) - - # return updated router - return new_router - - # NOTE(kevinbenton): workaround for eventlet/mysql deadlock. - # delete_router ends up calling _delete_port instead of delete_port. - @utils.synchronized('bsn-port-barrier') - def delete_router(self, context, router_id): - LOG.debug(_("NeutronRestProxyV2: delete_router() called")) - - with context.session.begin(subtransactions=True): - orig_router = self._get_router(context, router_id) - tenant_id = orig_router["tenant_id"] - - # Ensure that the router is not used - router_filter = {'router_id': [router_id]} - fips = self.get_floatingips_count(context.elevated(), - filters=router_filter) - if fips: - raise l3.RouterInUse(router_id=router_id) - - device_owner = l3_db.DEVICE_OWNER_ROUTER_INTF - device_filter = {'device_id': [router_id], - 'device_owner': [device_owner]} - ports = self.get_ports_count(context.elevated(), - filters=device_filter) - if ports: - raise l3.RouterInUse(router_id=router_id) - ret_val = super(NeutronRestProxyV2, - self).delete_router(context, router_id) - - # delete from network ctrl - self.servers.rest_delete_router(tenant_id, router_id) - return ret_val - - def add_router_interface(self, context, router_id, interface_info): - - LOG.debug(_("NeutronRestProxyV2: add_router_interface() called")) - - # Validate args - router = self._get_router(context, router_id) - tenant_id = router['tenant_id'] - - with context.session.begin(subtransactions=True): - # create interface in DB - new_intf_info = super(NeutronRestProxyV2, - self).add_router_interface(context, - router_id, - interface_info) - port = self._get_port(context, new_intf_info['port_id']) - net_id = port['network_id'] - subnet_id = new_intf_info['subnet_id'] - # we will use the port's network id as interface's id - interface_id = net_id - intf_details = self._get_router_intf_details(context, - interface_id, - subnet_id) - - # create interface on the network controller - self.servers.rest_add_router_interface(tenant_id, router_id, - intf_details) - return new_intf_info - - def remove_router_interface(self, context, router_id, interface_info): - - LOG.debug(_("NeutronRestProxyV2: remove_router_interface() called")) - - # Validate args - router = self._get_router(context, router_id) - tenant_id = router['tenant_id'] - - # we will first get the interface identifier before deleting in the DB - if not interface_info: - msg = _("Either subnet_id or port_id must be specified") - raise exceptions.BadRequest(resource='router', msg=msg) - if 'port_id' in interface_info: - port = self._get_port(context, interface_info['port_id']) - interface_id = port['network_id'] - elif 'subnet_id' in interface_info: - subnet = self._get_subnet(context, interface_info['subnet_id']) - interface_id = subnet['network_id'] - else: - msg = _("Either subnet_id or port_id must be specified") - raise exceptions.BadRequest(resource='router', msg=msg) - - with context.session.begin(subtransactions=True): - # remove router in DB - del_ret = super(NeutronRestProxyV2, - self).remove_router_interface(context, - router_id, - interface_info) - - # create router on the network controller - self.servers.rest_remove_router_interface(tenant_id, router_id, - interface_id) - return del_ret - - def create_floatingip(self, context, floatingip): - LOG.debug(_("NeutronRestProxyV2: create_floatingip() called")) - - with context.session.begin(subtransactions=True): - # create floatingip in DB - new_fl_ip = super(NeutronRestProxyV2, - self).create_floatingip(context, floatingip) - - # create floatingip on the network controller - try: - if 'floatingip' in self.servers.get_capabilities(): - self.servers.rest_create_floatingip( - new_fl_ip['tenant_id'], new_fl_ip) - else: - self._send_floatingip_update(context) - except servermanager.RemoteRestError as e: - with excutils.save_and_reraise_exception(): - LOG.error( - _("NeutronRestProxyV2: Unable to create remote " - "floating IP: %s"), e) - # return created floating IP - return new_fl_ip - - def update_floatingip(self, context, id, floatingip): - LOG.debug(_("NeutronRestProxyV2: update_floatingip() called")) - - with context.session.begin(subtransactions=True): - # update floatingip in DB - new_fl_ip = super(NeutronRestProxyV2, - self).update_floatingip(context, id, floatingip) - - # update network on network controller - if 'floatingip' in self.servers.get_capabilities(): - self.servers.rest_update_floatingip(new_fl_ip['tenant_id'], - new_fl_ip, id) - else: - self._send_floatingip_update(context) - return new_fl_ip - - def delete_floatingip(self, context, id): - LOG.debug(_("NeutronRestProxyV2: delete_floatingip() called")) - - with context.session.begin(subtransactions=True): - # delete floating IP in DB - old_fip = super(NeutronRestProxyV2, self).get_floatingip(context, - id) - super(NeutronRestProxyV2, self).delete_floatingip(context, id) - - # update network on network controller - if 'floatingip' in self.servers.get_capabilities(): - self.servers.rest_delete_floatingip(old_fip['tenant_id'], id) - else: - self._send_floatingip_update(context) - - def disassociate_floatingips(self, context, port_id): - LOG.debug(_("NeutronRestProxyV2: diassociate_floatingips() called")) - super(NeutronRestProxyV2, self).disassociate_floatingips(context, - port_id) - self._send_floatingip_update(context) - - # overriding method from l3_db as original method calls - # self.delete_floatingip() which in turn calls self.delete_port() which - # is locked with 'bsn-port-barrier' - def delete_disassociated_floatingips(self, context, network_id): - query = self._model_query(context, l3_db.FloatingIP) - query = query.filter_by(floating_network_id=network_id, - fixed_port_id=None, - router_id=None) - for fip in query: - context.session.delete(fip) - self._delete_port(context.elevated(), fip['floating_port_id']) - - def _send_floatingip_update(self, context): - try: - ext_net_id = self.get_external_network_id(context) - if ext_net_id: - # Use the elevated state of the context for the ext_net query - admin_context = context.elevated() - ext_net = super(NeutronRestProxyV2, - self).get_network(admin_context, ext_net_id) - # update external network on network controller - self._send_update_network(ext_net, admin_context) - except exceptions.TooManyExternalNetworks: - # get_external_network can raise errors when multiple external - # networks are detected, which isn't supported by the Plugin - LOG.error(_("NeutronRestProxyV2: too many external networks")) - - def _add_host_route(self, context, destination, port): - subnet = {} - for fixed_ip in port['fixed_ips']: - subnet_id = fixed_ip['subnet_id'] - nexthop = fixed_ip['ip_address'] - subnet['host_routes'] = [{'destination': destination, - 'nexthop': nexthop}] - updated_subnet = self.update_subnet(context, - subnet_id, - {'subnet': subnet}) - payload = {'subnet': updated_subnet} - self._dhcp_agent_notifier.notify(context, payload, - 'subnet.update.end') - LOG.debug(_("Adding host route: ")) - LOG.debug(_("Destination:%(dst)s nexthop:%(next)s"), - {'dst': destination, 'next': nexthop}) diff --git a/neutron/plugins/bigswitch/routerrule_db.py b/neutron/plugins/bigswitch/routerrule_db.py deleted file mode 100644 index e947a1f9d..000000000 --- a/neutron/plugins/bigswitch/routerrule_db.py +++ /dev/null @@ -1,148 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2013, Big Switch Networks -# 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 oslo.config import cfg -import sqlalchemy as sa -from sqlalchemy import orm - -from neutron.db import l3_db -from neutron.db import model_base -from neutron.openstack.common import log as logging -from neutron.plugins.bigswitch.extensions import routerrule - - -LOG = logging.getLogger(__name__) - - -class RouterRule(model_base.BASEV2): - id = sa.Column(sa.Integer, primary_key=True) - source = sa.Column(sa.String(64), nullable=False) - destination = sa.Column(sa.String(64), nullable=False) - nexthops = orm.relationship('NextHop', cascade='all,delete') - action = sa.Column(sa.String(10), nullable=False) - router_id = sa.Column(sa.String(36), - sa.ForeignKey('routers.id', - ondelete="CASCADE")) - - -class NextHop(model_base.BASEV2): - rule_id = sa.Column(sa.Integer, - sa.ForeignKey('routerrules.id', - ondelete="CASCADE"), - primary_key=True) - nexthop = sa.Column(sa.String(64), nullable=False, primary_key=True) - - -class RouterRule_db_mixin(l3_db.L3_NAT_db_mixin): - """ Mixin class to support route rule configuration on a router""" - def update_router(self, context, id, router): - r = router['router'] - with context.session.begin(subtransactions=True): - router_db = self._get_router(context, id) - if 'router_rules' in r: - self._update_router_rules(context, - router_db, - r['router_rules']) - updated = super(RouterRule_db_mixin, self).update_router( - context, id, router) - updated['router_rules'] = self._get_router_rules_by_router_id( - context, id) - - return updated - - def create_router(self, context, router): - r = router['router'] - with context.session.begin(subtransactions=True): - router_db = super(RouterRule_db_mixin, self).create_router( - context, router) - if 'router_rules' in r: - self._update_router_rules(context, - router_db, - r['router_rules']) - else: - LOG.debug(_('No rules in router')) - router_db['router_rules'] = self._get_router_rules_by_router_id( - context, router_db['id']) - - return router_db - - def _update_router_rules(self, context, router, rules): - if len(rules) > cfg.CONF.ROUTER.max_router_rules: - raise routerrule.RulesExhausted( - router_id=router['id'], - quota=cfg.CONF.ROUTER.max_router_rules) - del_context = context.session.query(RouterRule) - del_context.filter_by(router_id=router['id']).delete() - context.session.expunge_all() - LOG.debug(_('Updating router rules to %s'), rules) - for rule in rules: - router_rule = RouterRule( - router_id=router['id'], - destination=rule['destination'], - source=rule['source'], - action=rule['action']) - router_rule.nexthops = [NextHop(nexthop=hop) - for hop in rule['nexthops']] - context.session.add(router_rule) - context.session.flush() - - def _make_router_rule_list(self, router_rules): - ruleslist = [] - for rule in router_rules: - hops = [hop['nexthop'] for hop in rule['nexthops']] - ruleslist.append({'id': rule['id'], - 'destination': rule['destination'], - 'source': rule['source'], - 'action': rule['action'], - 'nexthops': hops}) - return ruleslist - - def _get_router_rules_by_router_id(self, context, id): - query = context.session.query(RouterRule) - router_rules = query.filter_by(router_id=id).all() - return self._make_router_rule_list(router_rules) - - def get_router(self, context, id, fields=None): - with context.session.begin(subtransactions=True): - router = super(RouterRule_db_mixin, self).get_router( - context, id, fields) - router['router_rules'] = self._get_router_rules_by_router_id( - context, id) - return router - - def get_routers(self, context, filters=None, fields=None, - sorts=None, limit=None, marker=None, - page_reverse=False): - with context.session.begin(subtransactions=True): - routers = super(RouterRule_db_mixin, self).get_routers( - context, filters, fields, sorts=sorts, limit=limit, - marker=marker, page_reverse=page_reverse) - for router in routers: - router['router_rules'] = self._get_router_rules_by_router_id( - context, router['id']) - return routers - - def get_sync_data(self, context, router_ids=None, active=None): - """Query routers and their related floating_ips, interfaces.""" - with context.session.begin(subtransactions=True): - routers = super(RouterRule_db_mixin, - self).get_sync_data(context, router_ids, - active=active) - for router in routers: - router['router_rules'] = self._get_router_rules_by_router_id( - context, router['id']) - return routers diff --git a/neutron/plugins/bigswitch/servermanager.py b/neutron/plugins/bigswitch/servermanager.py deleted file mode 100644 index caaa10133..000000000 --- a/neutron/plugins/bigswitch/servermanager.py +++ /dev/null @@ -1,595 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# Copyright 2014 Big Switch Networks, Inc. -# 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: Mandeep Dhami, Big Switch Networks, Inc. -# @author: Sumit Naiksatam, sumitnaiksatam@gmail.com, Big Switch Networks, Inc. -# @author: Kevin Benton, Big Switch Networks, Inc. - -""" -This module manages the HTTP and HTTPS connections to the backend controllers. - -The main class it provides for external use is ServerPool which manages a set -of ServerProxy objects that correspond to individual backend controllers. - -The following functionality is handled by this module: -- Translation of rest_* function calls to HTTP/HTTPS calls to the controllers -- Automatic failover between controllers -- SSL Certificate enforcement -- HTTP Authentication - -""" -import base64 -import httplib -import os -import socket -import ssl - -import eventlet -from oslo.config import cfg - -from neutron.common import exceptions -from neutron.common import utils -from neutron.openstack.common import excutils -from neutron.openstack.common import jsonutils as json -from neutron.openstack.common import log as logging -from neutron.plugins.bigswitch.db import consistency_db as cdb - -LOG = logging.getLogger(__name__) - -# The following are used to invoke the API on the external controller -CAPABILITIES_PATH = "/capabilities" -NET_RESOURCE_PATH = "/tenants/%s/networks" -PORT_RESOURCE_PATH = "/tenants/%s/networks/%s/ports" -ROUTER_RESOURCE_PATH = "/tenants/%s/routers" -ROUTER_INTF_OP_PATH = "/tenants/%s/routers/%s/interfaces" -NETWORKS_PATH = "/tenants/%s/networks/%s" -FLOATINGIPS_PATH = "/tenants/%s/floatingips/%s" -PORTS_PATH = "/tenants/%s/networks/%s/ports/%s" -ATTACHMENT_PATH = "/tenants/%s/networks/%s/ports/%s/attachment" -ROUTERS_PATH = "/tenants/%s/routers/%s" -ROUTER_INTF_PATH = "/tenants/%s/routers/%s/interfaces/%s" -TOPOLOGY_PATH = "/topology" -HEALTH_PATH = "/health" -SUCCESS_CODES = range(200, 207) -FAILURE_CODES = [0, 301, 302, 303, 400, 401, 403, 404, 500, 501, 502, 503, - 504, 505] -BASE_URI = '/networkService/v1.1' -ORCHESTRATION_SERVICE_ID = 'Neutron v2.0' -HASH_MATCH_HEADER = 'X-BSN-BVS-HASH-MATCH' -# error messages -NXNETWORK = 'NXVNS' - - -class RemoteRestError(exceptions.NeutronException): - message = _("Error in REST call to remote network " - "controller: %(reason)s") - status = None - - def __init__(self, **kwargs): - self.status = kwargs.pop('status', None) - self.reason = kwargs.get('reason') - super(RemoteRestError, self).__init__(**kwargs) - - -class ServerProxy(object): - """REST server proxy to a network controller.""" - - def __init__(self, server, port, ssl, auth, neutron_id, timeout, - base_uri, name, mypool, combined_cert): - self.server = server - self.port = port - self.ssl = ssl - self.base_uri = base_uri - self.timeout = timeout - self.name = name - self.success_codes = SUCCESS_CODES - self.auth = None - self.neutron_id = neutron_id - self.failed = False - self.capabilities = [] - # enable server to reference parent pool - self.mypool = mypool - # cache connection here to avoid a SSL handshake for every connection - self.currentconn = None - if auth: - self.auth = 'Basic ' + base64.encodestring(auth).strip() - self.combined_cert = combined_cert - - def get_capabilities(self): - try: - body = self.rest_call('GET', CAPABILITIES_PATH)[2] - self.capabilities = json.loads(body) - except Exception: - LOG.exception(_("Couldn't retrieve capabilities. " - "Newer API calls won't be supported.")) - LOG.info(_("The following capabilities were received " - "for %(server)s: %(cap)s"), {'server': self.server, - 'cap': self.capabilities}) - return self.capabilities - - def rest_call(self, action, resource, data='', headers={}, timeout=False, - reconnect=False): - uri = self.base_uri + resource - body = json.dumps(data) - if not headers: - headers = {} - headers['Content-type'] = 'application/json' - headers['Accept'] = 'application/json' - headers['NeutronProxy-Agent'] = self.name - headers['Instance-ID'] = self.neutron_id - headers['Orchestration-Service-ID'] = ORCHESTRATION_SERVICE_ID - headers[HASH_MATCH_HEADER] = self.mypool.consistency_hash or '' - if 'keep-alive' in self.capabilities: - headers['Connection'] = 'keep-alive' - else: - reconnect = True - if self.auth: - headers['Authorization'] = self.auth - - LOG.debug(_("ServerProxy: server=%(server)s, port=%(port)d, " - "ssl=%(ssl)r"), - {'server': self.server, 'port': self.port, 'ssl': self.ssl}) - LOG.debug(_("ServerProxy: resource=%(resource)s, data=%(data)r, " - "headers=%(headers)r, action=%(action)s"), - {'resource': resource, 'data': data, 'headers': headers, - 'action': action}) - - # unspecified timeout is False because a timeout can be specified as - # None to indicate no timeout. - if timeout is False: - timeout = self.timeout - - if timeout != self.timeout: - # need a new connection if timeout has changed - reconnect = True - - if not self.currentconn or reconnect: - if self.currentconn: - self.currentconn.close() - if self.ssl: - self.currentconn = HTTPSConnectionWithValidation( - self.server, self.port, timeout=timeout) - if self.currentconn is None: - LOG.error(_('ServerProxy: Could not establish HTTPS ' - 'connection')) - return 0, None, None, None - self.currentconn.combined_cert = self.combined_cert - else: - self.currentconn = httplib.HTTPConnection( - self.server, self.port, timeout=timeout) - if self.currentconn is None: - LOG.error(_('ServerProxy: Could not establish HTTP ' - 'connection')) - return 0, None, None, None - - try: - self.currentconn.request(action, uri, body, headers) - response = self.currentconn.getresponse() - newhash = response.getheader(HASH_MATCH_HEADER) - if newhash: - self._put_consistency_hash(newhash) - respstr = response.read() - respdata = respstr - if response.status in self.success_codes: - try: - respdata = json.loads(respstr) - except ValueError: - # response was not JSON, ignore the exception - pass - ret = (response.status, response.reason, respstr, respdata) - except httplib.HTTPException: - # If we were using a cached connection, try again with a new one. - with excutils.save_and_reraise_exception() as ctxt: - self.currentconn.close() - if reconnect: - # if reconnect is true, this was on a fresh connection so - # reraise since this server seems to be broken - ctxt.reraise = True - else: - # if reconnect is false, it was a cached connection so - # try one more time before re-raising - ctxt.reraise = False - return self.rest_call(action, resource, data, headers, - timeout=timeout, reconnect=True) - except (socket.timeout, socket.error) as e: - self.currentconn.close() - LOG.error(_('ServerProxy: %(action)s failure, %(e)r'), - {'action': action, 'e': e}) - ret = 0, None, None, None - LOG.debug(_("ServerProxy: status=%(status)d, reason=%(reason)r, " - "ret=%(ret)s, data=%(data)r"), {'status': ret[0], - 'reason': ret[1], - 'ret': ret[2], - 'data': ret[3]}) - return ret - - def _put_consistency_hash(self, newhash): - self.mypool.consistency_hash = newhash - cdb.put_consistency_hash(newhash) - - -class ServerPool(object): - - def __init__(self, timeout=False, - base_uri=BASE_URI, name='NeutronRestProxy'): - LOG.debug(_("ServerPool: initializing")) - # 'servers' is the list of network controller REST end-points - # (used in order specified till one succeeds, and it is sticky - # till next failure). Use 'server_auth' to encode api-key - servers = cfg.CONF.RESTPROXY.servers - self.auth = cfg.CONF.RESTPROXY.server_auth - self.ssl = cfg.CONF.RESTPROXY.server_ssl - self.neutron_id = cfg.CONF.RESTPROXY.neutron_id - self.base_uri = base_uri - self.name = name - self.timeout = cfg.CONF.RESTPROXY.server_timeout - self.always_reconnect = not cfg.CONF.RESTPROXY.cache_connections - default_port = 8000 - if timeout is not False: - self.timeout = timeout - - # Function to use to retrieve topology for consistency syncs. - # Needs to be set by module that uses the servermanager. - self.get_topo_function = None - self.get_topo_function_args = {} - - # Hash to send to backend with request as expected previous - # state to verify consistency. - self.consistency_hash = cdb.get_consistency_hash() - - if not servers: - raise cfg.Error(_('Servers not defined. Aborting server manager.')) - servers = [s if len(s.rsplit(':', 1)) == 2 - else "%s:%d" % (s, default_port) - for s in servers] - if any((len(spl) != 2 or not spl[1].isdigit()) - for spl in [sp.rsplit(':', 1) - for sp in servers]): - raise cfg.Error(_('Servers must be defined as :. ' - 'Configuration was %s') % servers) - self.servers = [ - self.server_proxy_for(server, int(port)) - for server, port in (s.rsplit(':', 1) for s in servers) - ] - eventlet.spawn(self._consistency_watchdog, - cfg.CONF.RESTPROXY.consistency_interval) - LOG.debug(_("ServerPool: initialization done")) - - def get_capabilities(self): - # lookup on first try - try: - return self.capabilities - except AttributeError: - # each server should return a list of capabilities it supports - # e.g. ['floatingip'] - capabilities = [set(server.get_capabilities()) - for server in self.servers] - # Pool only supports what all of the servers support - self.capabilities = set.intersection(*capabilities) - return self.capabilities - - def server_proxy_for(self, server, port): - combined_cert = self._get_combined_cert_for_server(server, port) - return ServerProxy(server, port, self.ssl, self.auth, self.neutron_id, - self.timeout, self.base_uri, self.name, mypool=self, - combined_cert=combined_cert) - - def _get_combined_cert_for_server(self, server, port): - # The ssl library requires a combined file with all trusted certs - # so we make one containing the trusted CAs and the corresponding - # host cert for this server - combined_cert = None - if self.ssl and not cfg.CONF.RESTPROXY.no_ssl_validation: - base_ssl = cfg.CONF.RESTPROXY.ssl_cert_directory - host_dir = os.path.join(base_ssl, 'host_certs') - ca_dir = os.path.join(base_ssl, 'ca_certs') - combined_dir = os.path.join(base_ssl, 'combined') - combined_cert = os.path.join(combined_dir, '%s.pem' % server) - if not os.path.exists(base_ssl): - raise cfg.Error(_('ssl_cert_directory [%s] does not exist. ' - 'Create it or disable ssl.') % base_ssl) - for automake in [combined_dir, ca_dir, host_dir]: - if not os.path.exists(automake): - os.makedirs(automake) - - # get all CA certs - certs = self._get_ca_cert_paths(ca_dir) - - # check for a host specific cert - hcert, exists = self._get_host_cert_path(host_dir, server) - if exists: - certs.append(hcert) - elif cfg.CONF.RESTPROXY.ssl_sticky: - self._fetch_and_store_cert(server, port, hcert) - certs.append(hcert) - if not certs: - raise cfg.Error(_('No certificates were found to verify ' - 'controller %s') % (server)) - self._combine_certs_to_file(certs, combined_cert) - return combined_cert - - def _combine_certs_to_file(self, certs, cfile): - ''' - Concatenates the contents of each certificate in a list of - certificate paths to one combined location for use with ssl - sockets. - ''' - with open(cfile, 'w') as combined: - for c in certs: - with open(c, 'r') as cert_handle: - combined.write(cert_handle.read()) - - def _get_host_cert_path(self, host_dir, server): - ''' - returns full path and boolean indicating existence - ''' - hcert = os.path.join(host_dir, '%s.pem' % server) - if os.path.exists(hcert): - return hcert, True - return hcert, False - - def _get_ca_cert_paths(self, ca_dir): - certs = [os.path.join(root, name) - for name in [ - name for (root, dirs, files) in os.walk(ca_dir) - for name in files - ] - if name.endswith('.pem')] - return certs - - def _fetch_and_store_cert(self, server, port, path): - ''' - Grabs a certificate from a server and writes it to - a given path. - ''' - try: - cert = ssl.get_server_certificate((server, port)) - except Exception as e: - raise cfg.Error(_('Could not retrieve initial ' - 'certificate from controller %(server)s. ' - 'Error details: %(error)s') % - {'server': server, 'error': str(e)}) - - LOG.warning(_("Storing to certificate for host %(server)s " - "at %(path)s") % {'server': server, - 'path': path}) - self._file_put_contents(path, cert) - - return cert - - def _file_put_contents(self, path, contents): - # Simple method to write to file. - # Created for easy Mocking - with open(path, 'w') as handle: - handle.write(contents) - - def server_failure(self, resp, ignore_codes=[]): - """Define failure codes as required. - - Note: We assume 301-303 is a failure, and try the next server in - the server pool. - """ - return (resp[0] in FAILURE_CODES and resp[0] not in ignore_codes) - - def action_success(self, resp): - """Defining success codes as required. - - Note: We assume any valid 2xx as being successful response. - """ - return resp[0] in SUCCESS_CODES - - @utils.synchronized('bsn-rest-call') - def rest_call(self, action, resource, data, headers, ignore_codes, - timeout=False): - good_first = sorted(self.servers, key=lambda x: x.failed) - first_response = None - for active_server in good_first: - ret = active_server.rest_call(action, resource, data, headers, - timeout, - reconnect=self.always_reconnect) - # If inconsistent, do a full synchronization - if ret[0] == httplib.CONFLICT: - if not self.get_topo_function: - raise cfg.Error(_('Server requires synchronization, ' - 'but no topology function was defined.')) - data = self.get_topo_function(**self.get_topo_function_args) - active_server.rest_call('PUT', TOPOLOGY_PATH, data, - timeout=None) - # Store the first response as the error to be bubbled up to the - # user since it was a good server. Subsequent servers will most - # likely be cluster slaves and won't have a useful error for the - # user (e.g. 302 redirect to master) - if not first_response: - first_response = ret - if not self.server_failure(ret, ignore_codes): - active_server.failed = False - return ret - else: - LOG.error(_('ServerProxy: %(action)s failure for servers: ' - '%(server)r Response: %(response)s'), - {'action': action, - 'server': (active_server.server, - active_server.port), - 'response': ret[3]}) - LOG.error(_("ServerProxy: Error details: status=%(status)d, " - "reason=%(reason)r, ret=%(ret)s, data=%(data)r"), - {'status': ret[0], 'reason': ret[1], 'ret': ret[2], - 'data': ret[3]}) - active_server.failed = True - - # All servers failed, reset server list and try again next time - LOG.error(_('ServerProxy: %(action)s failure for all servers: ' - '%(server)r'), - {'action': action, - 'server': tuple((s.server, - s.port) for s in self.servers)}) - return first_response - - def rest_action(self, action, resource, data='', errstr='%s', - ignore_codes=[], headers={}, timeout=False): - """ - Wrapper for rest_call that verifies success and raises a - RemoteRestError on failure with a provided error string - By default, 404 errors on DELETE calls are ignored because - they already do not exist on the backend. - """ - if not ignore_codes and action == 'DELETE': - ignore_codes = [404] - resp = self.rest_call(action, resource, data, headers, ignore_codes, - timeout) - if self.server_failure(resp, ignore_codes): - LOG.error(errstr, resp[2]) - raise RemoteRestError(reason=resp[2], status=resp[0]) - if resp[0] in ignore_codes: - LOG.warning(_("NeutronRestProxyV2: Received and ignored error " - "code %(code)s on %(action)s action to resource " - "%(resource)s"), - {'code': resp[2], 'action': action, - 'resource': resource}) - return resp - - def rest_create_router(self, tenant_id, router): - resource = ROUTER_RESOURCE_PATH % tenant_id - data = {"router": router} - errstr = _("Unable to create remote router: %s") - self.rest_action('POST', resource, data, errstr) - - def rest_update_router(self, tenant_id, router, router_id): - resource = ROUTERS_PATH % (tenant_id, router_id) - data = {"router": router} - errstr = _("Unable to update remote router: %s") - self.rest_action('PUT', resource, data, errstr) - - def rest_delete_router(self, tenant_id, router_id): - resource = ROUTERS_PATH % (tenant_id, router_id) - errstr = _("Unable to delete remote router: %s") - self.rest_action('DELETE', resource, errstr=errstr) - - def rest_add_router_interface(self, tenant_id, router_id, intf_details): - resource = ROUTER_INTF_OP_PATH % (tenant_id, router_id) - data = {"interface": intf_details} - errstr = _("Unable to add router interface: %s") - self.rest_action('POST', resource, data, errstr) - - def rest_remove_router_interface(self, tenant_id, router_id, interface_id): - resource = ROUTER_INTF_PATH % (tenant_id, router_id, interface_id) - errstr = _("Unable to delete remote intf: %s") - self.rest_action('DELETE', resource, errstr=errstr) - - def rest_create_network(self, tenant_id, network): - resource = NET_RESOURCE_PATH % tenant_id - data = {"network": network} - errstr = _("Unable to create remote network: %s") - self.rest_action('POST', resource, data, errstr) - - def rest_update_network(self, tenant_id, net_id, network): - resource = NETWORKS_PATH % (tenant_id, net_id) - data = {"network": network} - errstr = _("Unable to update remote network: %s") - self.rest_action('PUT', resource, data, errstr) - - def rest_delete_network(self, tenant_id, net_id): - resource = NETWORKS_PATH % (tenant_id, net_id) - errstr = _("Unable to update remote network: %s") - self.rest_action('DELETE', resource, errstr=errstr) - - def rest_create_port(self, tenant_id, net_id, port): - resource = ATTACHMENT_PATH % (tenant_id, net_id, port["id"]) - data = {"port": port} - device_id = port.get("device_id") - if not port["mac_address"] or not device_id: - # controller only cares about ports attached to devices - LOG.warning(_("No device MAC attached to port %s. " - "Skipping notification to controller."), port["id"]) - return - data["attachment"] = {"id": device_id, - "mac": port["mac_address"]} - errstr = _("Unable to create remote port: %s") - self.rest_action('PUT', resource, data, errstr) - - def rest_delete_port(self, tenant_id, network_id, port_id): - resource = ATTACHMENT_PATH % (tenant_id, network_id, port_id) - errstr = _("Unable to delete remote port: %s") - self.rest_action('DELETE', resource, errstr=errstr) - - def rest_update_port(self, tenant_id, net_id, port): - # Controller has no update operation for the port endpoint - # the create PUT method will replace - self.rest_create_port(tenant_id, net_id, port) - - def rest_create_floatingip(self, tenant_id, floatingip): - resource = FLOATINGIPS_PATH % (tenant_id, floatingip['id']) - errstr = _("Unable to create floating IP: %s") - self.rest_action('PUT', resource, errstr=errstr) - - def rest_update_floatingip(self, tenant_id, floatingip, oldid): - resource = FLOATINGIPS_PATH % (tenant_id, oldid) - errstr = _("Unable to update floating IP: %s") - self.rest_action('PUT', resource, errstr=errstr) - - def rest_delete_floatingip(self, tenant_id, oldid): - resource = FLOATINGIPS_PATH % (tenant_id, oldid) - errstr = _("Unable to delete floating IP: %s") - self.rest_action('DELETE', resource, errstr=errstr) - - def _consistency_watchdog(self, polling_interval=60): - if 'consistency' not in self.get_capabilities(): - LOG.warning(_("Backend server(s) do not support automated " - "consitency checks.")) - return - if not polling_interval: - LOG.warning(_("Consistency watchdog disabled by polling interval " - "setting of %s."), polling_interval) - return - while True: - # If consistency is supported, all we have to do is make any - # rest call and the consistency header will be added. If it - # doesn't match, the backend will return a synchronization error - # that will be handled by the rest_action. - eventlet.sleep(polling_interval) - try: - self.rest_action('GET', HEALTH_PATH) - except Exception: - LOG.exception(_("Encountered an error checking controller " - "health.")) - - -class HTTPSConnectionWithValidation(httplib.HTTPSConnection): - - # If combined_cert is None, the connection will continue without - # any certificate validation. - combined_cert = None - - def connect(self): - try: - sock = socket.create_connection((self.host, self.port), - self.timeout, self.source_address) - except AttributeError: - # python 2.6 doesn't have the source_address attribute - sock = socket.create_connection((self.host, self.port), - self.timeout) - if self._tunnel_host: - self.sock = sock - self._tunnel() - - if self.combined_cert: - self.sock = ssl.wrap_socket(sock, self.key_file, self.cert_file, - cert_reqs=ssl.CERT_REQUIRED, - ca_certs=self.combined_cert) - else: - self.sock = ssl.wrap_socket(sock, self.key_file, - self.cert_file, - cert_reqs=ssl.CERT_NONE) diff --git a/neutron/plugins/bigswitch/tests/__init__.py b/neutron/plugins/bigswitch/tests/__init__.py deleted file mode 100644 index 2a2421616..000000000 --- a/neutron/plugins/bigswitch/tests/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012 Big Switch Networks, Inc. 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. -# diff --git a/neutron/plugins/bigswitch/tests/test_server.py b/neutron/plugins/bigswitch/tests/test_server.py deleted file mode 100755 index ee0c2be3d..000000000 --- a/neutron/plugins/bigswitch/tests/test_server.py +++ /dev/null @@ -1,188 +0,0 @@ -#!/usr/bin/env python -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012, Big Switch Networks, Inc. -# 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: Mandeep Dhami, Big Switch Networks, Inc. - -"""Test server mocking a REST based network ctrl. - -Used for NeutronRestProxy tests -""" -from __future__ import print_function - -import re - -from six import moves -from wsgiref import simple_server - -from neutron.openstack.common import jsonutils as json - - -class TestNetworkCtrl(object): - - def __init__(self, host='', port=8000, - default_status='404 Not Found', - default_response='404 Not Found', - debug=False): - self.host = host - self.port = port - self.default_status = default_status - self.default_response = default_response - self.debug = debug - self.debug_env = False - self.debug_resp = False - self.matches = [] - - def match(self, prior, method_regexp, uri_regexp, handler, data=None, - multi=True): - """Add to the list of exptected inputs. - - The incoming request is matched in the order of priority. For same - priority, match the oldest match request first. - - :param prior: intgere priority of this match (e.g. 100) - :param method_regexp: regexp to match method (e.g. 'PUT|POST') - :param uri_regexp: regexp to match uri (e.g. '/quantum/v?.?/') - :param handler: function with signature: - lambda(method, uri, body, **kwargs) : status, body - where - - method: HTTP method for this request - - uri: URI for this HTTP request - - body: body of this HTTP request - - kwargs are: - - data: data object that was in the match call - - node: TestNetworkCtrl object itself - - id: offset of the matching tuple - and return values is: - (status, body) where: - - status: HTTP resp status (e.g. '200 OK'). - If None, use default_status - - body: HTTP resp body. If None, use '' - """ - assert int(prior) == prior, 'Priority should an integer be >= 0' - assert prior >= 0, 'Priority should an integer be >= 0' - - lo, hi = 0, len(self.matches) - while lo < hi: - mid = (lo + hi) // 2 - if prior < self.matches[mid]: - hi = mid - else: - lo = mid + 1 - self.matches.insert(lo, (prior, method_regexp, uri_regexp, handler, - data, multi)) - - def remove_id(self, id_): - assert id_ >= 0, 'remove_id: id < 0' - assert id_ <= len(self.matches), 'remove_id: id > len()' - self.matches.pop(id_) - - def request_handler(self, method, uri, body): - retstatus = self.default_status - retbody = self.default_response - for i in moves.xrange(len(self.matches)): - (prior, method_regexp, uri_regexp, handler, data, multi) = \ - self.matches[i] - if re.match(method_regexp, method) and re.match(uri_regexp, uri): - kwargs = { - 'data': data, - 'node': self, - 'id': i, - } - retstatus, retbody = handler(method, uri, body, **kwargs) - if multi is False: - self.remove_id(i) - break - if retbody is None: - retbody = '' - return (retstatus, retbody) - - def server(self): - def app(environ, start_response): - uri = environ['PATH_INFO'] - method = environ['REQUEST_METHOD'] - headers = [('Content-type', 'text/json')] - content_len_str = environ['CONTENT_LENGTH'] - - content_len = 0 - request_data = None - if content_len_str: - content_len = int(content_len_str) - request_data = environ.get('wsgi.input').read(content_len) - if request_data: - try: - request_data = json.loads(request_data) - except Exception: - # OK for it not to be json! Ignore it - pass - - if self.debug: - print('\n') - if self.debug_env: - print('environ:') - for (key, value) in sorted(environ.iteritems()): - print(' %16s : %s' % (key, value)) - - print('%s %s' % (method, uri)) - if request_data: - print('%s' % - json.dumps(request_data, sort_keys=True, indent=4)) - - status, body = self.request_handler(method, uri, None) - body_data = None - if body: - try: - body_data = json.loads(body) - except Exception: - # OK for it not to be json! Ignore it - pass - - start_response(status, headers) - if self.debug: - if self.debug_env: - print('%s: %s' % ('Response', - json.dumps(body_data, sort_keys=True, indent=4))) - return body - return simple_server.make_server(self.host, self.port, app) - - def run(self): - print("Serving on port %d ..." % self.port) - try: - self.server().serve_forever() - except KeyboardInterrupt: - pass - - -if __name__ == "__main__": - import sys - - port = 8899 - if len(sys.argv) > 1: - port = int(sys.argv[1]) - - debug = False - if len(sys.argv) > 2: - if sys.argv[2].lower() in ['debug', 'true']: - debug = True - - ctrl = TestNetworkCtrl(port=port, - default_status='200 OK', - default_response='{"status":"200 OK"}', - debug=debug) - ctrl.match(100, 'GET', '/test', - lambda m, u, b, **k: ('200 OK', '["200 OK"]')) - ctrl.run() diff --git a/neutron/plugins/bigswitch/vcsversion.py b/neutron/plugins/bigswitch/vcsversion.py deleted file mode 100644 index 6ed5e2680..000000000 --- a/neutron/plugins/bigswitch/vcsversion.py +++ /dev/null @@ -1,27 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2013 Big Switch Networks, Inc. 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: Sumit Naiksatam, sumitnaiksatam@gmail.com -# -version_info = {'branch_nick': u'neutron/trunk', - 'revision_id': u'1', - 'revno': 0} - - -NEUTRONRESTPROXY_VERSION = ['2013', '1', None] - - -FINAL = False # This becomes true at Release Candidate time diff --git a/neutron/plugins/bigswitch/version.py b/neutron/plugins/bigswitch/version.py deleted file mode 100755 index 2069d0bc8..000000000 --- a/neutron/plugins/bigswitch/version.py +++ /dev/null @@ -1,53 +0,0 @@ -#!/usr/bin/env python -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012 OpenStack Foundation -# Copyright 2012, Big Switch Networks, Inc. -# -# 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. -# -# Based on openstack generic code -# @author: Mandeep Dhami, Big Switch Networks, Inc. - -"""Determine version of NeutronRestProxy plugin""" -from __future__ import print_function - -from neutron.plugins.bigswitch import vcsversion - - -YEAR, COUNT, REVISION = vcsversion.NEUTRONRESTPROXY_VERSION - - -def canonical_version_string(): - return '.'.join(filter(None, - vcsversion.NEUTRONRESTPROXY_VERSION)) - - -def version_string(): - if vcsversion.FINAL: - return canonical_version_string() - else: - return '%s-dev' % (canonical_version_string(),) - - -def vcs_version_string(): - return "%s:%s" % (vcsversion.version_info['branch_nick'], - vcsversion.version_info['revision_id']) - - -def version_string_with_vcs(): - return "%s-%s" % (canonical_version_string(), vcs_version_string()) - - -if __name__ == "__main__": - print(version_string_with_vcs()) diff --git a/neutron/plugins/brocade/NeutronPlugin.py b/neutron/plugins/brocade/NeutronPlugin.py deleted file mode 100644 index c633085d0..000000000 --- a/neutron/plugins/brocade/NeutronPlugin.py +++ /dev/null @@ -1,497 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2013 Brocade Communications System, Inc. -# 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. -# -# Authors: -# Shiv Haris (sharis@brocade.com) -# Varma Bhupatiraju (vbhupati@#brocade.com) -# -# (Some parts adapted from LinuxBridge Plugin) -# TODO(shiv) need support for security groups - - -"""Implentation of Brocade Neutron Plugin.""" - -from oslo.config import cfg - -from neutron.agent import securitygroups_rpc as sg_rpc -from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api -from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api -from neutron.common import constants as q_const -from neutron.common import rpc_compat -from neutron.common import topics -from neutron.common import utils -from neutron.db import agents_db -from neutron.db import agentschedulers_db -from neutron.db import api as db -from neutron.db import db_base_plugin_v2 -from neutron.db import dhcp_rpc_base -from neutron.db import external_net_db -from neutron.db import extraroute_db -from neutron.db import l3_agentschedulers_db -from neutron.db import l3_rpc_base -from neutron.db import portbindings_base -from neutron.db import securitygroups_rpc_base as sg_db_rpc -from neutron.extensions import portbindings -from neutron.extensions import securitygroup as ext_sg -from neutron.openstack.common import context -from neutron.openstack.common import importutils -from neutron.openstack.common import log as logging -from neutron.plugins.brocade.db import models as brocade_db -from neutron.plugins.brocade import vlanbm as vbm -from neutron.plugins.common import constants as svc_constants - - -LOG = logging.getLogger(__name__) -PLUGIN_VERSION = 0.88 -AGENT_OWNER_PREFIX = "network:" -NOS_DRIVER = 'neutron.plugins.brocade.nos.nosdriver.NOSdriver' - -SWITCH_OPTS = [cfg.StrOpt('address', default='', - help=_('The address of the host to SSH to')), - cfg.StrOpt('username', default='', - help=_('The SSH username to use')), - cfg.StrOpt('password', default='', secret=True, - help=_('The SSH password to use')), - cfg.StrOpt('ostype', default='NOS', - help=_('Currently unused')) - ] - -PHYSICAL_INTERFACE_OPTS = [cfg.StrOpt('physical_interface', default='eth0', - help=_('The network interface to use when creating' - 'a port')) - ] - -cfg.CONF.register_opts(SWITCH_OPTS, "SWITCH") -cfg.CONF.register_opts(PHYSICAL_INTERFACE_OPTS, "PHYSICAL_INTERFACE") - - -class BridgeRpcCallbacks(rpc_compat.RpcCallback, - dhcp_rpc_base.DhcpRpcCallbackMixin, - l3_rpc_base.L3RpcCallbackMixin, - sg_db_rpc.SecurityGroupServerRpcCallbackMixin): - """Agent callback.""" - - RPC_API_VERSION = '1.1' - # Device names start with "tap" - # history - # 1.1 Support Security Group RPC - TAP_PREFIX_LEN = 3 - - @classmethod - def get_port_from_device(cls, device): - """Get port from the brocade specific db.""" - - # TODO(shh) context is not being passed as - # an argument to this function; - # - # need to be fixed in: - # file: neutron/db/securtygroups_rpc_base.py - # function: securitygroup_rules_for_devices() - # which needs to pass context to us - - # Doing what other plugins are doing - session = db.get_session() - port = brocade_db.get_port_from_device( - session, device[cls.TAP_PREFIX_LEN:]) - - # TODO(shiv): need to extend the db model to include device owners - # make it appears that the device owner is of type network - if port: - port['device'] = device - port['device_owner'] = AGENT_OWNER_PREFIX - port['binding:vif_type'] = 'bridge' - return port - - def get_device_details(self, rpc_context, **kwargs): - """Agent requests device details.""" - - agent_id = kwargs.get('agent_id') - device = kwargs.get('device') - LOG.debug(_("Device %(device)s details requested from %(agent_id)s"), - {'device': device, 'agent_id': agent_id}) - port = brocade_db.get_port(rpc_context, device[self.TAP_PREFIX_LEN:]) - if port: - entry = {'device': device, - 'vlan_id': port.vlan_id, - 'network_id': port.network_id, - 'port_id': port.port_id, - 'physical_network': port.physical_interface, - 'admin_state_up': port.admin_state_up - } - - else: - entry = {'device': device} - LOG.debug(_("%s can not be found in database"), device) - return entry - - def update_device_down(self, rpc_context, **kwargs): - """Device no longer exists on agent.""" - - device = kwargs.get('device') - port = self.get_port_from_device(device) - if port: - entry = {'device': device, - 'exists': True} - # Set port status to DOWN - port_id = port['port_id'] - brocade_db.update_port_state(rpc_context, port_id, False) - else: - entry = {'device': device, - 'exists': False} - LOG.debug(_("%s can not be found in database"), device) - return entry - - -class AgentNotifierApi(rpc_compat.RpcProxy, - sg_rpc.SecurityGroupAgentRpcApiMixin): - """Agent side of the linux bridge rpc API. - - API version history: - 1.0 - Initial version. - 1.1 - Added get_active_networks_info, create_dhcp_port, - and update_dhcp_port methods. - - """ - - BASE_RPC_API_VERSION = '1.1' - - def __init__(self, topic): - super(AgentNotifierApi, self).__init__( - topic=topic, default_version=self.BASE_RPC_API_VERSION) - self.topic = topic - self.topic_network_delete = topics.get_topic_name(topic, - topics.NETWORK, - topics.DELETE) - self.topic_port_update = topics.get_topic_name(topic, - topics.PORT, - topics.UPDATE) - - def network_delete(self, context, network_id): - self.fanout_cast(context, - self.make_msg('network_delete', - network_id=network_id), - topic=self.topic_network_delete) - - def port_update(self, context, port, physical_network, vlan_id): - self.fanout_cast(context, - self.make_msg('port_update', - port=port, - physical_network=physical_network, - vlan_id=vlan_id), - topic=self.topic_port_update) - - -class BrocadePluginV2(db_base_plugin_v2.NeutronDbPluginV2, - external_net_db.External_net_db_mixin, - extraroute_db.ExtraRoute_db_mixin, - sg_db_rpc.SecurityGroupServerRpcMixin, - l3_agentschedulers_db.L3AgentSchedulerDbMixin, - agentschedulers_db.DhcpAgentSchedulerDbMixin, - portbindings_base.PortBindingBaseMixin): - """BrocadePluginV2 is a Neutron plugin. - - Provides L2 Virtual Network functionality using VDX. Upper - layer driver class that interfaces to NETCONF layer below. - - """ - - def __init__(self): - """Initialize Brocade Plugin. - - Specify switch address and db configuration. - """ - - super(BrocadePluginV2, self).__init__() - self.supported_extension_aliases = ["binding", "security-group", - "external-net", "router", - "extraroute", "agent", - "l3_agent_scheduler", - "dhcp_agent_scheduler"] - - self.physical_interface = (cfg.CONF.PHYSICAL_INTERFACE. - physical_interface) - self.base_binding_dict = self._get_base_binding_dict() - portbindings_base.register_port_dict_function() - self.ctxt = context.get_admin_context() - self.ctxt.session = db.get_session() - self._vlan_bitmap = vbm.VlanBitmap(self.ctxt) - self._setup_rpc() - self.network_scheduler = importutils.import_object( - cfg.CONF.network_scheduler_driver - ) - self.router_scheduler = importutils.import_object( - cfg.CONF.router_scheduler_driver - ) - self.brocade_init() - - def brocade_init(self): - """Brocade specific initialization.""" - - self._switch = {'address': cfg.CONF.SWITCH.address, - 'username': cfg.CONF.SWITCH.username, - 'password': cfg.CONF.SWITCH.password - } - self._driver = importutils.import_object(NOS_DRIVER) - - def _setup_rpc(self): - # RPC support - self.service_topics = {svc_constants.CORE: topics.PLUGIN, - svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN} - self.rpc_context = context.RequestContext('neutron', 'neutron', - is_admin=False) - self.conn = rpc_compat.create_connection(new=True) - self.endpoints = [BridgeRpcCallbacks(), - agents_db.AgentExtRpcCallback()] - for svc_topic in self.service_topics.values(): - self.conn.create_consumer(svc_topic, self.endpoints, fanout=False) - # Consume from all consumers in threads - self.conn.consume_in_threads() - self.notifier = AgentNotifierApi(topics.AGENT) - self.agent_notifiers[q_const.AGENT_TYPE_DHCP] = ( - dhcp_rpc_agent_api.DhcpAgentNotifyAPI() - ) - self.agent_notifiers[q_const.AGENT_TYPE_L3] = ( - l3_rpc_agent_api.L3AgentNotifyAPI() - ) - - def create_network(self, context, network): - """Create network. - - This call to create network translates to creation of port-profile on - the physical switch. - """ - - with context.session.begin(subtransactions=True): - net = super(BrocadePluginV2, self).create_network(context, network) - net_uuid = net['id'] - vlan_id = self._vlan_bitmap.get_next_vlan(None) - switch = self._switch - try: - self._driver.create_network(switch['address'], - switch['username'], - switch['password'], - vlan_id) - except Exception: - # Proper formatting - LOG.exception(_("Brocade NOS driver error")) - LOG.debug(_("Returning the allocated vlan (%d) to the pool"), - vlan_id) - self._vlan_bitmap.release_vlan(int(vlan_id)) - raise Exception(_("Brocade plugin raised exception, " - "check logs")) - - brocade_db.create_network(context, net_uuid, vlan_id) - self._process_l3_create(context, net, network['network']) - - LOG.info(_("Allocated vlan (%d) from the pool"), vlan_id) - return net - - def delete_network(self, context, net_id): - """Delete network. - - This call to delete the network translates to removing the - port-profile on the physical switch. - """ - - with context.session.begin(subtransactions=True): - self._process_l3_delete(context, net_id) - result = super(BrocadePluginV2, self).delete_network(context, - net_id) - # we must delete all ports in db first (foreign key constraint) - # there is no need to delete port in the driver (its a no-op) - # (actually: note there is no such call to the driver) - bports = brocade_db.get_ports(context, net_id) - for bport in bports: - brocade_db.delete_port(context, bport['port_id']) - - # find the vlan for this network - net = brocade_db.get_network(context, net_id) - vlan_id = net['vlan'] - - # Tell hw to do remove PP - switch = self._switch - try: - self._driver.delete_network(switch['address'], - switch['username'], - switch['password'], - vlan_id) - except Exception: - # Proper formatting - LOG.exception(_("Brocade NOS driver error")) - raise Exception(_("Brocade plugin raised exception, " - "check logs")) - - # now ok to delete the network - brocade_db.delete_network(context, net_id) - - # relinquish vlan in bitmap - self._vlan_bitmap.release_vlan(int(vlan_id)) - return result - - def update_network(self, context, id, network): - - session = context.session - with session.begin(subtransactions=True): - net = super(BrocadePluginV2, self).update_network(context, id, - network) - self._process_l3_update(context, net, network['network']) - return net - - def create_port(self, context, port): - """Create logical port on the switch.""" - - tenant_id = port['port']['tenant_id'] - network_id = port['port']['network_id'] - admin_state_up = port['port']['admin_state_up'] - - physical_interface = self.physical_interface - - with context.session.begin(subtransactions=True): - bnet = brocade_db.get_network(context, network_id) - vlan_id = bnet['vlan'] - - neutron_port = super(BrocadePluginV2, self).create_port(context, - port) - self._process_portbindings_create_and_update(context, - port['port'], - neutron_port) - interface_mac = neutron_port['mac_address'] - port_id = neutron_port['id'] - - switch = self._switch - - # convert mac format: xx:xx:xx:xx:xx:xx -> xxxx.xxxx.xxxx - mac = self.mac_reformat_62to34(interface_mac) - try: - self._driver.associate_mac_to_network(switch['address'], - switch['username'], - switch['password'], - vlan_id, - mac) - except Exception: - # Proper formatting - LOG.exception(_("Brocade NOS driver error")) - raise Exception(_("Brocade plugin raised exception, " - "check logs")) - - # save to brocade persistent db - brocade_db.create_port(context, port_id, network_id, - physical_interface, - vlan_id, tenant_id, admin_state_up) - - # apply any extensions - return neutron_port - - def delete_port(self, context, port_id): - with context.session.begin(subtransactions=True): - neutron_port = self.get_port(context, port_id) - interface_mac = neutron_port['mac_address'] - # convert mac format: xx:xx:xx:xx:xx:xx -> xxxx.xxxx.xxxx - mac = self.mac_reformat_62to34(interface_mac) - - brocade_port = brocade_db.get_port(context, port_id) - vlan_id = brocade_port['vlan_id'] - - switch = self._switch - try: - self._driver.dissociate_mac_from_network(switch['address'], - switch['username'], - switch['password'], - vlan_id, - mac) - except Exception: - LOG.exception(_("Brocade NOS driver error")) - raise Exception( - _("Brocade plugin raised exception, check logs")) - - super(BrocadePluginV2, self).delete_port(context, port_id) - brocade_db.delete_port(context, port_id) - - def update_port(self, context, port_id, port): - original_port = self.get_port(context, port_id) - session = context.session - port_updated = False - with session.begin(subtransactions=True): - # delete the port binding and read it with the new rules - if ext_sg.SECURITYGROUPS in port['port']: - port['port'][ext_sg.SECURITYGROUPS] = ( - self._get_security_groups_on_port(context, port)) - self._delete_port_security_group_bindings(context, port_id) - # process_port_create_security_group also needs port id - port['port']['id'] = port_id - self._process_port_create_security_group( - context, - port['port'], - port['port'][ext_sg.SECURITYGROUPS]) - port_updated = True - port_data = port['port'] - port = super(BrocadePluginV2, self).update_port( - context, port_id, port) - self._process_portbindings_create_and_update(context, - port_data, - port) - if original_port['admin_state_up'] != port['admin_state_up']: - port_updated = True - - if (original_port['fixed_ips'] != port['fixed_ips'] or - not utils.compare_elements( - original_port.get(ext_sg.SECURITYGROUPS), - port.get(ext_sg.SECURITYGROUPS))): - self.notifier.security_groups_member_updated( - context, port.get(ext_sg.SECURITYGROUPS)) - - if port_updated: - self._notify_port_updated(context, port) - - return port - - def _notify_port_updated(self, context, port): - port_id = port['id'] - bport = brocade_db.get_port(context, port_id) - self.notifier.port_update(context, port, - bport.physical_interface, - bport.vlan_id) - - def _get_base_binding_dict(self): - binding = { - portbindings.VIF_TYPE: portbindings.VIF_TYPE_BRIDGE, - portbindings.VIF_DETAILS: { - # TODO(rkukura): Replace with new VIF security details - portbindings.CAP_PORT_FILTER: - 'security-group' in self.supported_extension_aliases}} - return binding - - def get_plugin_version(self): - """Get version number of the plugin.""" - return PLUGIN_VERSION - - @staticmethod - def mac_reformat_62to34(interface_mac): - """Transform MAC address format. - - Transforms from 6 groups of 2 hexadecimal numbers delimited by ":" - to 3 groups of 4 hexadecimals numbers delimited by ".". - - :param interface_mac: MAC address in the format xx:xx:xx:xx:xx:xx - :type interface_mac: string - :returns: MAC address in the format xxxx.xxxx.xxxx - :rtype: string - """ - - mac = interface_mac.replace(":", "") - mac = mac[0:4] + "." + mac[4:8] + "." + mac[8:12] - return mac diff --git a/neutron/plugins/brocade/README.md b/neutron/plugins/brocade/README.md deleted file mode 100644 index 82b3ad89d..000000000 --- a/neutron/plugins/brocade/README.md +++ /dev/null @@ -1,112 +0,0 @@ -Brocade Openstack Neutron Plugin -================================ - -* up-to-date version of these instructions are located at: - http://wiki.openstack.org/brocade-neutron-plugin - -* N.B.: Please see Prerequisites section regarding ncclient (netconf client library) - -* Supports VCS (Virtual Cluster of Switches) - - -Openstack Brocade Neutron Plugin implements the Neutron v2.0 API. - -This plugin is meant to orchestrate Brocade VCS switches running NOS, examples of these are: - - 1. VDX 67xx series of switches - 2. VDX 87xx series of switches - -Brocade Neutron plugin implements the Neutron v2.0 API. It uses NETCONF at the backend -to configure the Brocade switch. - - +------------+ +------------+ +-------------+ - | | | | | | - | | | | | Brocade | - | Openstack | v2.0 | Brocade | NETCONF | VCS Switch | - | Neutron +--------+ Neutron +----------+ | - | | | Plugin | | VDX 67xx | - | | | | | VDX 87xx | - | | | | | | - | | | | | | - +------------+ +------------+ +-------------+ - - -Directory Structure -=================== - -Normally you will have your Openstack directory structure as follows: - - /opt/stack/nova/ - /opt/stack/horizon/ - ... - /opt/stack/neutron/neutron/plugins/ - -Within this structure, Brocade plugin resides at: - - /opt/stack/neutron/neutron/plugins/brocade - - -Prerequsites -============ - -This plugin requires installation of the python netconf client (ncclient) library: - -ncclient v0.3.1 - Python library for NETCONF clients available at http://github.com/brocade/ncclient - - % git clone https://www.github.com/brocade/ncclient - % cd ncclient; sudo python ./setup.py install - - -Configuration -============= - -1. Specify to Neutron that you will be using the Brocade Plugin - this is done -by setting the parameter core_plugin in Neutron: - - core_plugin = neutron.plugins.brocade.NeutronPlugin.BrocadePluginV2 - -2. Physical switch configuration parameters and Brocade specific database configuration is specified in -the configuration file specified in the brocade.ini files: - - % cat /etc/neutron/plugins/brocade/brocade.ini - [SWITCH] - username = admin - password = password - address = - ostype = NOS - - [database] - connection = mysql://root:pass@localhost/brocade_neutron?charset=utf8 - - (please see list of more configuration parameters in the brocade.ini file) - -Running Setup.py -================ - -Running setup.py with appropriate permissions will copy the default configuration -file to /etc/neutron/plugins/brocade/brocade.ini. This file MUST be edited to -suit your setup/environment. - - % cd /opt/stack/neutron/neutron/plugins/brocade - % python setup.py - - -Devstack -======== - -Please see special notes for devstack at: -http://wiki.openstack.org/brocade-neutron-plugin - -In order to use Brocade Neutron Plugin, add the following lines in localrc, if localrc file doe - not exist create one: - -ENABLED_SERVICES=g-api,g-reg,key,n-api,n-crt,n-obj,n-cpu,n-net,n-cond,cinder,c-sch,c-api,c-vol,n-sch,n-novnc,n-xvnc,n-cauth,horizon,rabbit,neutron,q-svc,q-agt -Q_PLUGIN=brocade - -As part of running devstack/stack.sh, the configuration files is copied as: - - % cp /opt/stack/neutron/etc/neutron/plugins/brocade/brocade.ini /etc/neutron/plugins/brocade/brocade.ini - -(hence it is important to make any changes to the configuration in: -/opt/stack/neutron/etc/neutron/plugins/brocade/brocade.ini) - diff --git a/neutron/plugins/brocade/__init__.py b/neutron/plugins/brocade/__init__.py deleted file mode 100644 index c22f863e3..000000000 --- a/neutron/plugins/brocade/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2013 Brocade Communications System, Inc. -# 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. diff --git a/neutron/plugins/brocade/db/__init__.py b/neutron/plugins/brocade/db/__init__.py deleted file mode 100644 index c22f863e3..000000000 --- a/neutron/plugins/brocade/db/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2013 Brocade Communications System, Inc. -# 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. diff --git a/neutron/plugins/brocade/db/models.py b/neutron/plugins/brocade/db/models.py deleted file mode 100644 index d9b3663a1..000000000 --- a/neutron/plugins/brocade/db/models.py +++ /dev/null @@ -1,151 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2013 Brocade Communications System, Inc. -# 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. -# -# Authors: -# Shiv Haris (sharis@brocade.com) -# Varma Bhupatiraju (vbhupati@#brocade.com) - - -"""Brocade specific database schema/model.""" - -import sqlalchemy as sa - -from neutron.db import model_base -from neutron.db import models_v2 - - -class BrocadeNetwork(model_base.BASEV2, models_v2.HasId): - """Schema for brocade network.""" - - vlan = sa.Column(sa.String(10)) - - -class BrocadePort(model_base.BASEV2): - """Schema for brocade port.""" - - port_id = sa.Column(sa.String(36), primary_key=True, default="") - network_id = sa.Column(sa.String(36), - sa.ForeignKey("brocadenetworks.id"), - nullable=False) - admin_state_up = sa.Column(sa.Boolean, nullable=False) - physical_interface = sa.Column(sa.String(36)) - vlan_id = sa.Column(sa.String(36)) - tenant_id = sa.Column(sa.String(36)) - - -def create_network(context, net_id, vlan): - """Create a brocade specific network/port-profiles.""" - - session = context.session - with session.begin(subtransactions=True): - net = BrocadeNetwork(id=net_id, vlan=vlan) - session.add(net) - - return net - - -def delete_network(context, net_id): - """Delete a brocade specific network/port-profiles.""" - - session = context.session - with session.begin(subtransactions=True): - net = (session.query(BrocadeNetwork).filter_by(id=net_id).first()) - if net is not None: - session.delete(net) - - -def get_network(context, net_id, fields=None): - """Get brocade specific network, with vlan extension.""" - - session = context.session - return (session.query(BrocadeNetwork).filter_by(id=net_id).first()) - - -def get_networks(context, filters=None, fields=None): - """Get all brocade specific networks.""" - - session = context.session - try: - nets = session.query(BrocadeNetwork).all() - return nets - except sa.exc.SQLAlchemyError: - return None - - -def create_port(context, port_id, network_id, physical_interface, - vlan_id, tenant_id, admin_state_up): - """Create a brocade specific port, has policy like vlan.""" - - # port_id is truncated: since the linux-bridge tap device names are - # based on truncated port id, this enables port lookups using - # tap devices - port_id = port_id[0:11] - session = context.session - with session.begin(subtransactions=True): - port = BrocadePort(port_id=port_id, - network_id=network_id, - physical_interface=physical_interface, - vlan_id=vlan_id, - admin_state_up=admin_state_up, - tenant_id=tenant_id) - session.add(port) - return port - - -def get_port(context, port_id): - """get a brocade specific port.""" - - port_id = port_id[0:11] - session = context.session - port = (session.query(BrocadePort).filter_by(port_id=port_id).first()) - return port - - -def get_ports(context, network_id=None): - """get a brocade specific port.""" - - session = context.session - ports = (session.query(BrocadePort).filter_by(network_id=network_id).all()) - return ports - - -def delete_port(context, port_id): - """delete brocade specific port.""" - - port_id = port_id[0:11] - session = context.session - with session.begin(subtransactions=True): - port = (session.query(BrocadePort).filter_by(port_id=port_id).first()) - if port is not None: - session.delete(port) - - -def get_port_from_device(session, port_id): - """get port from the tap device.""" - - # device is same as truncated port_id - port = (session.query(BrocadePort).filter_by(port_id=port_id).first()) - return port - - -def update_port_state(context, port_id, admin_state_up): - """Update port attributes.""" - - port_id = port_id[0:11] - session = context.session - session.query(BrocadePort).filter_by( - port_id=port_id).update({'admin_state_up': admin_state_up}) diff --git a/neutron/plugins/brocade/nos/__init__.py b/neutron/plugins/brocade/nos/__init__.py deleted file mode 100644 index 9d4562b0d..000000000 --- a/neutron/plugins/brocade/nos/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright (c) 2013 Brocade Communications Systems, Inc. -# 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. diff --git a/neutron/plugins/brocade/nos/fake_nosdriver.py b/neutron/plugins/brocade/nos/fake_nosdriver.py deleted file mode 100644 index 8984768d5..000000000 --- a/neutron/plugins/brocade/nos/fake_nosdriver.py +++ /dev/null @@ -1,117 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2013 Brocade Communications System, Inc. -# 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. -# -# Authors: -# Varma Bhupatiraju (vbhupati@#brocade.com) -# Shiv Haris (sharis@brocade.com) - - -"""FAKE DRIVER, for unit tests purposes. - -Brocade NOS Driver implements NETCONF over SSHv2 for -Neutron network life-cycle management. -""" - - -class NOSdriver(): - """NOS NETCONF interface driver for Neutron network. - - Fake: Handles life-cycle management of Neutron network, - leverages AMPP on NOS - (for use by unit tests, avoids touching any hardware) - """ - - def __init__(self): - pass - - def connect(self, host, username, password): - """Connect via SSH and initialize the NETCONF session.""" - pass - - def create_network(self, host, username, password, net_id): - """Creates a new virtual network.""" - pass - - def delete_network(self, host, username, password, net_id): - """Deletes a virtual network.""" - pass - - def associate_mac_to_network(self, host, username, password, - net_id, mac): - """Associates a MAC address to virtual network.""" - pass - - def dissociate_mac_from_network(self, host, username, password, - net_id, mac): - """Dissociates a MAC address from virtual network.""" - pass - - def create_vlan_interface(self, mgr, vlan_id): - """Configures a VLAN interface.""" - pass - - def delete_vlan_interface(self, mgr, vlan_id): - """Deletes a VLAN interface.""" - pass - - def get_port_profiles(self, mgr): - """Retrieves all port profiles.""" - pass - - def get_port_profile(self, mgr, name): - """Retrieves a port profile.""" - pass - - def create_port_profile(self, mgr, name): - """Creates a port profile.""" - pass - - def delete_port_profile(self, mgr, name): - """Deletes a port profile.""" - pass - - def activate_port_profile(self, mgr, name): - """Activates a port profile.""" - pass - - def deactivate_port_profile(self, mgr, name): - """Deactivates a port profile.""" - pass - - def associate_mac_to_port_profile(self, mgr, name, mac_address): - """Associates a MAC address to a port profile.""" - pass - - def dissociate_mac_from_port_profile(self, mgr, name, mac_address): - """Dissociates a MAC address from a port profile.""" - pass - - def create_vlan_profile_for_port_profile(self, mgr, name): - """Creates VLAN sub-profile for port profile.""" - pass - - def configure_l2_mode_for_vlan_profile(self, mgr, name): - """Configures L2 mode for VLAN sub-profile.""" - pass - - def configure_trunk_mode_for_vlan_profile(self, mgr, name): - """Configures trunk mode for VLAN sub-profile.""" - pass - - def configure_allowed_vlans_for_vlan_profile(self, mgr, name, vlan_id): - """Configures allowed VLANs for VLAN sub-profile.""" - pass diff --git a/neutron/plugins/brocade/nos/nctemplates.py b/neutron/plugins/brocade/nos/nctemplates.py deleted file mode 100644 index 48071dbcd..000000000 --- a/neutron/plugins/brocade/nos/nctemplates.py +++ /dev/null @@ -1,204 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright (c) 2013 Brocade Communications Systems, Inc. -# 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. -# -# Authors: -# Varma Bhupatiraju (vbhupati@#brocade.com) -# Shiv Haris (sharis@brocade.com) - - -"""NOS NETCONF XML Configuration Command Templates. - -Interface Configuration Commands -""" - -# Create VLAN (vlan_id) -CREATE_VLAN_INTERFACE = """ - - - - - {vlan_id} - - - - -""" - -# Delete VLAN (vlan_id) -DELETE_VLAN_INTERFACE = """ - - - - - {vlan_id} - - - - -""" - -# -# AMPP Life-cycle Management Configuration Commands -# - -# Create AMPP port-profile (port_profile_name) -CREATE_PORT_PROFILE = """ - - - {name} - - -""" - -# Create VLAN sub-profile for port-profile (port_profile_name) -CREATE_VLAN_PROFILE_FOR_PORT_PROFILE = """ - - - {name} - - - -""" - -# Configure L2 mode for VLAN sub-profile (port_profile_name) -CONFIGURE_L2_MODE_FOR_VLAN_PROFILE = """ - - - {name} - - - - - -""" - -# Configure trunk mode for VLAN sub-profile (port_profile_name) -CONFIGURE_TRUNK_MODE_FOR_VLAN_PROFILE = """ - - - {name} - - - - trunk - - - - - -""" - -# Configure allowed VLANs for VLAN sub-profile -# (port_profile_name, allowed_vlan, native_vlan) -CONFIGURE_ALLOWED_VLANS_FOR_VLAN_PROFILE = """ - - - {name} - - - - - - {vlan_id} - - - - - - - -""" - -# Delete port-profile (port_profile_name) -DELETE_PORT_PROFILE = """ - - - {name} - - -""" - -# Activate port-profile (port_profile_name) -ACTIVATE_PORT_PROFILE = """ - - - - {name} - - - - -""" - -# Deactivate port-profile (port_profile_name) -DEACTIVATE_PORT_PROFILE = """ - - - - {name} - - - - -""" - -# Associate MAC address to port-profile (port_profile_name, mac_address) -ASSOCIATE_MAC_TO_PORT_PROFILE = """ - - - - {name} - - {mac_address} - - - - -""" - -# Dissociate MAC address from port-profile (port_profile_name, mac_address) -DISSOCIATE_MAC_FROM_PORT_PROFILE = """ - - - - {name} - - {mac_address} - - - - -""" - -# -# Custom RPC Commands -# - - -# -# Constants -# - -# Port profile naming convention for Neutron networks -OS_PORT_PROFILE_NAME = "openstack-profile-{id}" - -# Port profile filter expressions -PORT_PROFILE_XPATH_FILTER = "/port-profile" -PORT_PROFILE_NAME_XPATH_FILTER = "/port-profile[name='{name}']" diff --git a/neutron/plugins/brocade/nos/nosdriver.py b/neutron/plugins/brocade/nos/nosdriver.py deleted file mode 100644 index ce4c86110..000000000 --- a/neutron/plugins/brocade/nos/nosdriver.py +++ /dev/null @@ -1,233 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2013 Brocade Communications System, Inc. -# 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. -# -# Authors: -# Varma Bhupatiraju (vbhupati@#brocade.com) -# Shiv Haris (sharis@brocade.com) - - -"""Brocade NOS Driver implements NETCONF over SSHv2 for -Neutron network life-cycle management. -""" - -from ncclient import manager - -from neutron.openstack.common import excutils -from neutron.openstack.common import log as logging -from neutron.plugins.brocade.nos import nctemplates as template - - -LOG = logging.getLogger(__name__) -SSH_PORT = 22 - - -def nos_unknown_host_cb(host, fingerprint): - """An unknown host callback. - - Returns `True` if it finds the key acceptable, - and `False` if not. This default callback for NOS always returns 'True' - (i.e. trusts all hosts for now). - """ - return True - - -class NOSdriver(): - """NOS NETCONF interface driver for Neutron network. - - Handles life-cycle management of Neutron network (leverages AMPP on NOS) - """ - - def __init__(self): - self.mgr = None - - def connect(self, host, username, password): - """Connect via SSH and initialize the NETCONF session.""" - - # Use the persisted NETCONF connection - if self.mgr and self.mgr.connected: - return self.mgr - - # Open new NETCONF connection - try: - self.mgr = manager.connect(host=host, port=SSH_PORT, - username=username, password=password, - unknown_host_cb=nos_unknown_host_cb) - except Exception as e: - with excutils.save_and_reraise_exception(): - LOG.error(_("Connect failed to switch: %s"), e) - - LOG.debug(_("Connect success to host %(host)s:%(ssh_port)d"), - dict(host=host, ssh_port=SSH_PORT)) - return self.mgr - - def close_session(self): - """Close NETCONF session.""" - if self.mgr: - self.mgr.close_session() - self.mgr = None - - def create_network(self, host, username, password, net_id): - """Creates a new virtual network.""" - - name = template.OS_PORT_PROFILE_NAME.format(id=net_id) - try: - mgr = self.connect(host, username, password) - self.create_vlan_interface(mgr, net_id) - self.create_port_profile(mgr, name) - self.create_vlan_profile_for_port_profile(mgr, name) - self.configure_l2_mode_for_vlan_profile(mgr, name) - self.configure_trunk_mode_for_vlan_profile(mgr, name) - self.configure_allowed_vlans_for_vlan_profile(mgr, name, net_id) - self.activate_port_profile(mgr, name) - except Exception as ex: - with excutils.save_and_reraise_exception(): - LOG.exception(_("NETCONF error: %s"), ex) - self.close_session() - - def delete_network(self, host, username, password, net_id): - """Deletes a virtual network.""" - - name = template.OS_PORT_PROFILE_NAME.format(id=net_id) - try: - mgr = self.connect(host, username, password) - self.deactivate_port_profile(mgr, name) - self.delete_port_profile(mgr, name) - self.delete_vlan_interface(mgr, net_id) - except Exception as ex: - with excutils.save_and_reraise_exception(): - LOG.exception(_("NETCONF error: %s"), ex) - self.close_session() - - def associate_mac_to_network(self, host, username, password, - net_id, mac): - """Associates a MAC address to virtual network.""" - - name = template.OS_PORT_PROFILE_NAME.format(id=net_id) - try: - mgr = self.connect(host, username, password) - self.associate_mac_to_port_profile(mgr, name, mac) - except Exception as ex: - with excutils.save_and_reraise_exception(): - LOG.exception(_("NETCONF error: %s"), ex) - self.close_session() - - def dissociate_mac_from_network(self, host, username, password, - net_id, mac): - """Dissociates a MAC address from virtual network.""" - - name = template.OS_PORT_PROFILE_NAME.format(id=net_id) - try: - mgr = self.connect(host, username, password) - self.dissociate_mac_from_port_profile(mgr, name, mac) - except Exception as ex: - with excutils.save_and_reraise_exception(): - LOG.exception(_("NETCONF error: %s"), ex) - self.close_session() - - def create_vlan_interface(self, mgr, vlan_id): - """Configures a VLAN interface.""" - - confstr = template.CREATE_VLAN_INTERFACE.format(vlan_id=vlan_id) - mgr.edit_config(target='running', config=confstr) - - def delete_vlan_interface(self, mgr, vlan_id): - """Deletes a VLAN interface.""" - - confstr = template.DELETE_VLAN_INTERFACE.format(vlan_id=vlan_id) - mgr.edit_config(target='running', config=confstr) - - def get_port_profiles(self, mgr): - """Retrieves all port profiles.""" - - filterstr = template.PORT_PROFILE_XPATH_FILTER - response = mgr.get_config(source='running', - filter=('xpath', filterstr)).data_xml - return response - - def get_port_profile(self, mgr, name): - """Retrieves a port profile.""" - - filterstr = template.PORT_PROFILE_NAME_XPATH_FILTER.format(name=name) - response = mgr.get_config(source='running', - filter=('xpath', filterstr)).data_xml - return response - - def create_port_profile(self, mgr, name): - """Creates a port profile.""" - - confstr = template.CREATE_PORT_PROFILE.format(name=name) - mgr.edit_config(target='running', config=confstr) - - def delete_port_profile(self, mgr, name): - """Deletes a port profile.""" - - confstr = template.DELETE_PORT_PROFILE.format(name=name) - mgr.edit_config(target='running', config=confstr) - - def activate_port_profile(self, mgr, name): - """Activates a port profile.""" - - confstr = template.ACTIVATE_PORT_PROFILE.format(name=name) - mgr.edit_config(target='running', config=confstr) - - def deactivate_port_profile(self, mgr, name): - """Deactivates a port profile.""" - - confstr = template.DEACTIVATE_PORT_PROFILE.format(name=name) - mgr.edit_config(target='running', config=confstr) - - def associate_mac_to_port_profile(self, mgr, name, mac_address): - """Associates a MAC address to a port profile.""" - - confstr = template.ASSOCIATE_MAC_TO_PORT_PROFILE.format( - name=name, mac_address=mac_address) - mgr.edit_config(target='running', config=confstr) - - def dissociate_mac_from_port_profile(self, mgr, name, mac_address): - """Dissociates a MAC address from a port profile.""" - - confstr = template.DISSOCIATE_MAC_FROM_PORT_PROFILE.format( - name=name, mac_address=mac_address) - mgr.edit_config(target='running', config=confstr) - - def create_vlan_profile_for_port_profile(self, mgr, name): - """Creates VLAN sub-profile for port profile.""" - - confstr = template.CREATE_VLAN_PROFILE_FOR_PORT_PROFILE.format( - name=name) - mgr.edit_config(target='running', config=confstr) - - def configure_l2_mode_for_vlan_profile(self, mgr, name): - """Configures L2 mode for VLAN sub-profile.""" - - confstr = template.CONFIGURE_L2_MODE_FOR_VLAN_PROFILE.format( - name=name) - mgr.edit_config(target='running', config=confstr) - - def configure_trunk_mode_for_vlan_profile(self, mgr, name): - """Configures trunk mode for VLAN sub-profile.""" - - confstr = template.CONFIGURE_TRUNK_MODE_FOR_VLAN_PROFILE.format( - name=name) - mgr.edit_config(target='running', config=confstr) - - def configure_allowed_vlans_for_vlan_profile(self, mgr, name, vlan_id): - """Configures allowed VLANs for VLAN sub-profile.""" - - confstr = template.CONFIGURE_ALLOWED_VLANS_FOR_VLAN_PROFILE.format( - name=name, vlan_id=vlan_id) - mgr.edit_config(target='running', config=confstr) diff --git a/neutron/plugins/brocade/tests/README b/neutron/plugins/brocade/tests/README deleted file mode 100644 index 476ca0535..000000000 --- a/neutron/plugins/brocade/tests/README +++ /dev/null @@ -1,24 +0,0 @@ -Start the neutron-server with IP address of switch configured in brocade.ini: -(for configuration instruction please see README.md in the above directory) - -nostest.py: -This tests two things: - 1. Creates port-profile on the physical switch when a neutron 'network' is created - 2. Associates the MAC address with the created port-profile - -noscli.py: - CLI interface to create/delete/associate MAC/dissociate MAC - Commands: - % noscli.py create - (after running check that PP is created on the switch) - - % noscli.py delete - (after running check that PP is deleted from the switch) - - % noscli.py associate - (after running check that MAC is associated with PP) - - % noscli.py dissociate - (after running check that MAC is dissociated from the PP) - - diff --git a/neutron/plugins/brocade/tests/noscli.py b/neutron/plugins/brocade/tests/noscli.py deleted file mode 100644 index 81e988e3c..000000000 --- a/neutron/plugins/brocade/tests/noscli.py +++ /dev/null @@ -1,93 +0,0 @@ -#!/usr/bin/env python -# -# Copyright (c) 2013 Brocade Communications Systems, Inc. -# 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. -# -# Authors: -# Varma Bhupatiraju (vbhupati@#brocade.com) -# Shiv Haris (sharis@brocade.com) - - -"""Brocade NOS Driver CLI.""" -from __future__ import print_function - -import argparse - -from neutron.openstack.common import log as logging -from neutron.plugins.brocade.nos import nosdriver as nos - -LOG = logging.getLogger(__name__) - - -class NOSCli(object): - - def __init__(self, host, username, password): - self.host = host - self.username = username - self.password = password - self.driver = nos.NOSdriver() - - def execute(self, cmd): - numargs = len(args.otherargs) - - if args.cmd == 'create' and numargs == 1: - self._create(args.otherargs[0]) - elif args.cmd == 'delete' and numargs == 1: - self._delete(args.otherargs[0]) - elif args.cmd == 'associate' and numargs == 2: - self._associate(args.otherargs[0], args.otherargs[1]) - elif args.cmd == 'dissociate' and numargs == 2: - self._dissociate(args.otherargs[0], args.otherargs[1]) - else: - print(usage_desc) - exit(0) - - def _create(self, net_id): - self.driver.create_network(self.host, self.username, self.password, - net_id) - - def _delete(self, net_id): - self.driver.delete_network(self.host, self.username, self.password, - net_id) - - def _associate(self, net_id, mac): - self.driver.associate_mac_to_network( - self.host, self.username, self.password, net_id, mac) - - def _dissociate(self, net_id, mac): - self.driver.dissociate_mac_from_network( - self.host, self.username, self.password, net_id, mac) - - -usage_desc = """ -Command descriptions: - - create - delete - associate - dissociate -""" - -parser = argparse.ArgumentParser(description='process args', - usage=usage_desc, epilog='foo bar help') -parser.add_argument('--ip', default='localhost') -parser.add_argument('--username', default='admin') -parser.add_argument('--password', default='password') -parser.add_argument('cmd') -parser.add_argument('otherargs', nargs='*') -args = parser.parse_args() - -noscli = NOSCli(args.ip, args.username, args.password) -noscli.execute(args.cmd) diff --git a/neutron/plugins/brocade/tests/nostest.py b/neutron/plugins/brocade/tests/nostest.py deleted file mode 100644 index 72a21ae8b..000000000 --- a/neutron/plugins/brocade/tests/nostest.py +++ /dev/null @@ -1,48 +0,0 @@ -# Copyright (c) 2013 Brocade Communications Systems, Inc. -# 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. -# -# Authors: -# Varma Bhupatiraju (vbhupati@#brocade.com) -# Shiv Haris (sharis@brocade.com) - - -"""Brocade NOS Driver Test.""" -from __future__ import print_function - -import sys - -from neutron.plugins.brocade.nos import nosdriver as nos - - -def nostest(host, username, password): - # Driver - driver = nos.NOSdriver() - - # Neutron operations - vlan = 1001 - mac = '0050.56bf.0001' - driver.create_network(host, username, password, vlan) - driver.associate_mac_to_network(host, username, password, vlan, mac) - driver.dissociate_mac_from_network(host, username, password, vlan, mac) - driver.delete_network(host, username, password, vlan) - - # AMPP enumeration - with driver.connect(host, username, password) as mgr: - print(driver.get_port_profiles(mgr)) - print(driver.get_port_profile(mgr, 'default')) - - -if __name__ == '__main__': - nostest(sys.argv[1], sys.argv[2], sys.argv[3]) diff --git a/neutron/plugins/brocade/vlanbm.py b/neutron/plugins/brocade/vlanbm.py deleted file mode 100644 index 3c4b3ccb6..000000000 --- a/neutron/plugins/brocade/vlanbm.py +++ /dev/null @@ -1,60 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2013 Brocade Communications System, Inc. -# 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. -# -# Authors: -# Shiv Haris (sharis@brocade.com) -# Varma Bhupatiraju (vbhupati@#brocade.com) - - -"""A Vlan Bitmap class to handle allocation/de-allocation of vlan ids.""" -from six import moves - -from neutron.common import constants -from neutron.plugins.brocade.db import models as brocade_db - - -MIN_VLAN = constants.MIN_VLAN_TAG + 1 -MAX_VLAN = constants.MAX_VLAN_TAG - - -class VlanBitmap(object): - """Setup a vlan bitmap for allocation/de-allocation.""" - - # Keep track of the vlans that have been allocated/de-allocated - # uses a bitmap to do this - - def __init__(self, ctxt): - """Initialize the vlan as a set.""" - self.vlans = set(int(net['vlan']) - for net in brocade_db.get_networks(ctxt) - if net['vlan'] - ) - - def get_next_vlan(self, vlan_id=None): - """Try to get a specific vlan if requested or get the next vlan.""" - min_vlan_search = vlan_id or MIN_VLAN - max_vlan_search = (vlan_id and vlan_id + 1) or MAX_VLAN - - for vlan in moves.xrange(min_vlan_search, max_vlan_search): - if vlan not in self.vlans: - self.vlans.add(vlan) - return vlan - - def release_vlan(self, vlan_id): - """Return the vlan to the pool.""" - if vlan_id in self.vlans: - self.vlans.remove(vlan_id) diff --git a/neutron/plugins/cisco/README b/neutron/plugins/cisco/README deleted file mode 100644 index 2bedb75b1..000000000 --- a/neutron/plugins/cisco/README +++ /dev/null @@ -1,7 +0,0 @@ -Cisco Neutron Virtual Network Plugin - -This plugin implements Neutron v2 APIs and helps configure -topologies consisting of virtual and physical switches. - -For more details on use please refer to: -http://wiki.openstack.org/cisco-neutron diff --git a/neutron/plugins/cisco/__init__.py b/neutron/plugins/cisco/__init__.py deleted file mode 100644 index db695fb0a..000000000 --- a/neutron/plugins/cisco/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 Cisco Systems, Inc. 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: Sumit Naiksatam, Cisco Systems, Inc. -# diff --git a/neutron/plugins/cisco/common/__init__.py b/neutron/plugins/cisco/common/__init__.py deleted file mode 100644 index 833357b73..000000000 --- a/neutron/plugins/cisco/common/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 Cisco Systems, Inc. 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: Sumit Naiksatam, Cisco Systems, Inc. diff --git a/neutron/plugins/cisco/common/cisco_constants.py b/neutron/plugins/cisco/common/cisco_constants.py deleted file mode 100644 index 2f1992108..000000000 --- a/neutron/plugins/cisco/common/cisco_constants.py +++ /dev/null @@ -1,111 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 Cisco Systems, Inc. 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: Sumit Naiksatam, Cisco Systems, Inc. - - -# Attachment attributes -INSTANCE_ID = 'instance_id' -TENANT_ID = 'tenant_id' -TENANT_NAME = 'tenant_name' -HOST_NAME = 'host_name' - -# Network attributes -NET_ID = 'id' -NET_NAME = 'name' -NET_VLAN_ID = 'vlan_id' -NET_VLAN_NAME = 'vlan_name' -NET_PORTS = 'ports' - -CREDENTIAL_ID = 'credential_id' -CREDENTIAL_NAME = 'credential_name' -CREDENTIAL_USERNAME = 'user_name' -CREDENTIAL_PASSWORD = 'password' -CREDENTIAL_TYPE = 'type' -MASKED_PASSWORD = '********' - -USERNAME = 'username' -PASSWORD = 'password' - -LOGGER_COMPONENT_NAME = "cisco_plugin" - -NEXUS_PLUGIN = 'nexus_plugin' -VSWITCH_PLUGIN = 'vswitch_plugin' - -DEVICE_IP = 'device_ip' - -NETWORK_ADMIN = 'network_admin' - -NETWORK = 'network' -PORT = 'port' -BASE_PLUGIN_REF = 'base_plugin_ref' -CONTEXT = 'context' -SUBNET = 'subnet' - -#### N1Kv CONSTANTS -# Special vlan_id value in n1kv_vlan_allocations table indicating flat network -FLAT_VLAN_ID = -1 - -# Topic for tunnel notifications between the plugin and agent -TUNNEL = 'tunnel' - -# Maximum VXLAN range configurable for one network profile. -MAX_VXLAN_RANGE = 1000000 - -# Values for network_type -NETWORK_TYPE_FLAT = 'flat' -NETWORK_TYPE_VLAN = 'vlan' -NETWORK_TYPE_VXLAN = 'vxlan' -NETWORK_TYPE_LOCAL = 'local' -NETWORK_TYPE_NONE = 'none' -NETWORK_TYPE_TRUNK = 'trunk' -NETWORK_TYPE_MULTI_SEGMENT = 'multi-segment' - -# Values for network sub_type -NETWORK_TYPE_OVERLAY = 'overlay' -NETWORK_SUBTYPE_NATIVE_VXLAN = 'native_vxlan' -NETWORK_SUBTYPE_TRUNK_VLAN = NETWORK_TYPE_VLAN -NETWORK_SUBTYPE_TRUNK_VXLAN = NETWORK_TYPE_OVERLAY - -# Prefix for VM Network name -VM_NETWORK_NAME_PREFIX = 'vmn_' - -DEFAULT_HTTP_TIMEOUT = 15 -SET = 'set' -INSTANCE = 'instance' -PROPERTIES = 'properties' -NAME = 'name' -ID = 'id' -POLICY = 'policy' -TENANT_ID_NOT_SET = 'TENANT_ID_NOT_SET' -ENCAPSULATIONS = 'encapsulations' -STATE = 'state' -ONLINE = 'online' -MAPPINGS = 'mappings' -MAPPING = 'mapping' -SEGMENTS = 'segments' -SEGMENT = 'segment' -BRIDGE_DOMAIN_SUFFIX = '_bd' -LOGICAL_NETWORK_SUFFIX = '_log_net' -ENCAPSULATION_PROFILE_SUFFIX = '_profile' - -UUID_LENGTH = 36 - -# Nexus vlan and vxlan segment range -NEXUS_VLAN_RESERVED_MIN = 3968 -NEXUS_VLAN_RESERVED_MAX = 4047 -NEXUS_VXLAN_MIN = 4096 -NEXUS_VXLAN_MAX = 16000000 diff --git a/neutron/plugins/cisco/common/cisco_credentials_v2.py b/neutron/plugins/cisco/common/cisco_credentials_v2.py deleted file mode 100644 index 5d8fc8ff5..000000000 --- a/neutron/plugins/cisco/common/cisco_credentials_v2.py +++ /dev/null @@ -1,61 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012 Cisco Systems, Inc. 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: Sumit Naiksatam, Cisco Systems, Inc. - -import logging as LOG - -from neutron.plugins.cisco.common import cisco_constants as const -from neutron.plugins.cisco.common import cisco_exceptions as cexc -from neutron.plugins.cisco.common import config -from neutron.plugins.cisco.db import network_db_v2 as cdb - -LOG.basicConfig(level=LOG.WARN) -LOG.getLogger(const.LOGGER_COMPONENT_NAME) - - -class Store(object): - """Credential Store.""" - - @staticmethod - def initialize(): - dev_dict = config.get_device_dictionary() - for key in dev_dict: - dev_id, dev_ip, dev_key = key - if dev_key == const.USERNAME: - try: - cdb.add_credential( - dev_ip, - dev_dict[dev_id, dev_ip, const.USERNAME], - dev_dict[dev_id, dev_ip, const.PASSWORD], - dev_id) - except cexc.CredentialAlreadyExists: - # We are quietly ignoring this, since it only happens - # if this class module is loaded more than once, in - # which case, the credentials are already populated - pass - - @staticmethod - def get_username(cred_name): - """Get the username.""" - credential = cdb.get_credential_name(cred_name) - return credential[const.CREDENTIAL_USERNAME] - - @staticmethod - def get_password(cred_name): - """Get the password.""" - credential = cdb.get_credential_name(cred_name) - return credential[const.CREDENTIAL_PASSWORD] diff --git a/neutron/plugins/cisco/common/cisco_exceptions.py b/neutron/plugins/cisco/common/cisco_exceptions.py deleted file mode 100644 index be50e7665..000000000 --- a/neutron/plugins/cisco/common/cisco_exceptions.py +++ /dev/null @@ -1,236 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 Cisco Systems, Inc. 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: Sumit Naiksatam, Cisco Systems, Inc. -# @author: Rohit Agarwalla, Cisco Systems, Inc. - -"""Exceptions used by the Cisco plugin.""" - -from neutron.common import exceptions - - -class NetworkSegmentIDNotFound(exceptions.NeutronException): - """Segmentation ID for network is not found.""" - message = _("Segmentation ID for network %(net_id)s is not found.") - - -class NoMoreNics(exceptions.NeutronException): - """No more dynamic NICs are available in the system.""" - message = _("Unable to complete operation. No more dynamic NICs are " - "available in the system.") - - -class NetworkVlanBindingAlreadyExists(exceptions.NeutronException): - """Binding cannot be created, since it already exists.""" - message = _("NetworkVlanBinding for %(vlan_id)s and network " - "%(network_id)s already exists.") - - -class VlanIDNotFound(exceptions.NeutronException): - """VLAN ID cannot be found.""" - message = _("Vlan ID %(vlan_id)s not found.") - - -class VlanIDOutsidePool(exceptions.NeutronException): - """VLAN ID cannot be allocated, since it is outside the configured pool.""" - message = _("Unable to complete operation. VLAN ID exists outside of the " - "configured network segment range.") - - -class VlanIDNotAvailable(exceptions.NeutronException): - """No VLAN ID available.""" - message = _("No Vlan ID available.") - - -class QosNotFound(exceptions.NeutronException): - """QoS level with this ID cannot be found.""" - message = _("QoS level %(qos_id)s could not be found " - "for tenant %(tenant_id)s.") - - -class QosNameAlreadyExists(exceptions.NeutronException): - """QoS Name already exists.""" - message = _("QoS level with name %(qos_name)s already exists " - "for tenant %(tenant_id)s.") - - -class CredentialNotFound(exceptions.NeutronException): - """Credential with this ID cannot be found.""" - message = _("Credential %(credential_id)s could not be found.") - - -class CredentialNameNotFound(exceptions.NeutronException): - """Credential Name could not be found.""" - message = _("Credential %(credential_name)s could not be found.") - - -class CredentialAlreadyExists(exceptions.NeutronException): - """Credential already exists.""" - message = _("Credential %(credential_name)s already exists.") - - -class ProviderNetworkExists(exceptions.NeutronException): - """Provider network already exists.""" - message = _("Provider network %s already exists") - - -class NexusComputeHostNotConfigured(exceptions.NeutronException): - """Connection to compute host is not configured.""" - message = _("Connection to %(host)s is not configured.") - - -class NexusConnectFailed(exceptions.NeutronException): - """Failed to connect to Nexus switch.""" - message = _("Unable to connect to Nexus %(nexus_host)s. Reason: %(exc)s.") - - -class NexusConfigFailed(exceptions.NeutronException): - """Failed to configure Nexus switch.""" - message = _("Failed to configure Nexus: %(config)s. Reason: %(exc)s.") - - -class NexusPortBindingNotFound(exceptions.NeutronException): - """NexusPort Binding is not present.""" - message = _("Nexus Port Binding (%(filters)s) is not present.") - - def __init__(self, **kwargs): - filters = ','.join('%s=%s' % i for i in kwargs.items()) - super(NexusPortBindingNotFound, self).__init__(filters=filters) - - -class NoNexusSviSwitch(exceptions.NeutronException): - """No usable nexus switch found.""" - message = _("No usable Nexus switch found to create SVI interface.") - - -class PortVnicBindingAlreadyExists(exceptions.NeutronException): - """PortVnic Binding already exists.""" - message = _("PortVnic Binding %(port_id)s already exists.") - - -class PortVnicNotFound(exceptions.NeutronException): - """PortVnic Binding is not present.""" - message = _("PortVnic Binding %(port_id)s is not present.") - - -class SubnetNotSpecified(exceptions.NeutronException): - """Subnet id not specified.""" - message = _("No subnet_id specified for router gateway.") - - -class SubnetInterfacePresent(exceptions.NeutronException): - """Subnet SVI interface already exists.""" - message = _("Subnet %(subnet_id)s has an interface on %(router_id)s.") - - -class PortIdForNexusSvi(exceptions.NeutronException): - """Port Id specified for Nexus SVI.""" - message = _('Nexus hardware router gateway only uses Subnet Ids.') - - -class InvalidDetach(exceptions.NeutronException): - message = _("Unable to unplug the attachment %(att_id)s from port " - "%(port_id)s for network %(net_id)s. The attachment " - "%(att_id)s does not exist.") - - -class PolicyProfileAlreadyExists(exceptions.NeutronException): - """Policy Profile cannot be created since it already exists.""" - message = _("Policy Profile %(profile_id)s " - "already exists.") - - -class PolicyProfileIdNotFound(exceptions.NotFound): - """Policy Profile with the given UUID cannot be found.""" - message = _("Policy Profile %(profile_id)s could not be found.") - - -class NetworkProfileAlreadyExists(exceptions.NeutronException): - """Network Profile cannot be created since it already exists.""" - message = _("Network Profile %(profile_id)s " - "already exists.") - - -class NetworkProfileNotFound(exceptions.NotFound): - """Network Profile with the given UUID/name cannot be found.""" - message = _("Network Profile %(profile)s could not be found.") - - -class NetworkProfileInUse(exceptions.InUse): - """Network Profile with the given UUID is in use.""" - message = _("One or more network segments belonging to network " - "profile %(profile)s is in use.") - - -class NoMoreNetworkSegments(exceptions.NoNetworkAvailable): - """Network segments exhausted for the given network profile.""" - message = _("No more segments available in network segment pool " - "%(network_profile_name)s.") - - -class VMNetworkNotFound(exceptions.NotFound): - """VM Network with the given name cannot be found.""" - message = _("VM Network %(name)s could not be found.") - - -class VxlanIDInUse(exceptions.InUse): - """VXLAN ID is in use.""" - message = _("Unable to create the network. " - "The VXLAN ID %(vxlan_id)s is in use.") - - -class VxlanIDNotFound(exceptions.NotFound): - """VXLAN ID cannot be found.""" - message = _("Vxlan ID %(vxlan_id)s not found.") - - -class VxlanIDOutsidePool(exceptions.NeutronException): - """VXLAN ID cannot be allocated, as it is outside the configured pool.""" - message = _("Unable to complete operation. VXLAN ID exists outside of the " - "configured network segment range.") - - -class VSMConnectionFailed(exceptions.ServiceUnavailable): - """Connection to VSM failed.""" - message = _("Connection to VSM failed: %(reason)s.") - - -class VSMError(exceptions.NeutronException): - """Error has occurred on the VSM.""" - message = _("Internal VSM Error: %(reason)s.") - - -class NetworkBindingNotFound(exceptions.NotFound): - """Network Binding for network cannot be found.""" - message = _("Network Binding for network %(network_id)s could " - "not be found.") - - -class PortBindingNotFound(exceptions.NotFound): - """Port Binding for port cannot be found.""" - message = _("Port Binding for port %(port_id)s could " - "not be found.") - - -class ProfileTenantBindingNotFound(exceptions.NotFound): - """Profile to Tenant binding for given profile ID cannot be found.""" - message = _("Profile-Tenant binding for profile %(profile_id)s could " - "not be found.") - - -class NoClusterFound(exceptions.NotFound): - """No service cluster found to perform multi-segment bridging.""" - message = _("No service cluster found to perform multi-segment bridging.") diff --git a/neutron/plugins/cisco/common/cisco_faults.py b/neutron/plugins/cisco/common/cisco_faults.py deleted file mode 100644 index 80e787e41..000000000 --- a/neutron/plugins/cisco/common/cisco_faults.py +++ /dev/null @@ -1,138 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 Cisco Systems, Inc. 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: Ying Liu, Cisco Systems, Inc. - -import webob.dec - -from neutron import wsgi - - -class Fault(webob.exc.HTTPException): - """Error codes for API faults.""" - - _fault_names = { - 400: "malformedRequest", - 401: "unauthorized", - 451: "CredentialNotFound", - 452: "QoSNotFound", - 453: "NovatenantNotFound", - 454: "MultiportNotFound", - 470: "serviceUnavailable", - 471: "pluginFault" - } - - def __init__(self, exception): - """Create a Fault for the given webob.exc.exception.""" - self.wrapped_exc = exception - - @webob.dec.wsgify(RequestClass=wsgi.Request) - def __call__(self, req): - """Generate a WSGI response. - - Response is generated based on the exception passed to constructor. - """ - # Replace the body with fault details. - code = self.wrapped_exc.status_int - fault_name = self._fault_names.get(code, "neutronServiceFault") - fault_data = { - fault_name: { - 'code': code, - 'message': self.wrapped_exc.explanation}} - # 'code' is an attribute on the fault tag itself - content_type = req.best_match_content_type() - self.wrapped_exc.body = wsgi.Serializer().serialize( - fault_data, content_type) - self.wrapped_exc.content_type = content_type - return self.wrapped_exc - - -class PortNotFound(webob.exc.HTTPClientError): - """PortNotFound exception. - - subclass of :class:`~HTTPClientError` - - This indicates that the server did not find the port specified - in the HTTP request for a given network - - code: 430, title: Port not Found - """ - code = 430 - title = _('Port not Found') - explanation = _('Unable to find a port with the specified identifier.') - - -class CredentialNotFound(webob.exc.HTTPClientError): - """CredentialNotFound exception. - - subclass of :class:`~HTTPClientError` - - This indicates that the server did not find the Credential specified - in the HTTP request - - code: 451, title: Credential not Found - """ - code = 451 - title = _('Credential Not Found') - explanation = _('Unable to find a Credential with' - ' the specified identifier.') - - -class QosNotFound(webob.exc.HTTPClientError): - """QosNotFound exception. - - subclass of :class:`~HTTPClientError` - - This indicates that the server did not find the QoS specified - in the HTTP request - - code: 452, title: QoS not Found - """ - code = 452 - title = _('QoS Not Found') - explanation = _('Unable to find a QoS with' - ' the specified identifier.') - - -class NovatenantNotFound(webob.exc.HTTPClientError): - """NovatenantNotFound exception. - - subclass of :class:`~HTTPClientError` - - This indicates that the server did not find the Novatenant specified - in the HTTP request - - code: 453, title: Nova tenant not Found - """ - code = 453 - title = _('Nova tenant Not Found') - explanation = _('Unable to find a Novatenant with' - ' the specified identifier.') - - -class RequestedStateInvalid(webob.exc.HTTPClientError): - """RequestedStateInvalid exception. - - subclass of :class:`~HTTPClientError` - - This indicates that the server could not update the port state to - to the request value - - code: 431, title: Requested State Invalid - """ - code = 431 - title = _('Requested State Invalid') - explanation = _('Unable to update port state with specified value.') diff --git a/neutron/plugins/cisco/common/config.py b/neutron/plugins/cisco/common/config.py deleted file mode 100644 index f13569cea..000000000 --- a/neutron/plugins/cisco/common/config.py +++ /dev/null @@ -1,151 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cisco Systems, Inc. -# -# 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 oslo.config import cfg - -from neutron.agent.common import config - - -cisco_plugins_opts = [ - cfg.StrOpt('vswitch_plugin', - default='neutron.plugins.openvswitch.ovs_neutron_plugin.' - 'OVSNeutronPluginV2', - help=_("Virtual Switch to use")), - cfg.StrOpt('nexus_plugin', - default='neutron.plugins.cisco.nexus.cisco_nexus_plugin_v2.' - 'NexusPlugin', - help=_("Nexus Switch to use")), -] - -cisco_opts = [ - cfg.StrOpt('vlan_name_prefix', default='q-', - help=_("VLAN Name prefix")), - cfg.StrOpt('provider_vlan_name_prefix', default='p-', - help=_("VLAN Name prefix for provider vlans")), - cfg.BoolOpt('provider_vlan_auto_create', default=True, - help=_('Provider VLANs are automatically created as needed ' - 'on the Nexus switch')), - cfg.BoolOpt('provider_vlan_auto_trunk', default=True, - help=_('Provider VLANs are automatically trunked as needed ' - 'on the ports of the Nexus switch')), - cfg.BoolOpt('nexus_l3_enable', default=False, - help=_("Enable L3 support on the Nexus switches")), - cfg.BoolOpt('svi_round_robin', default=False, - help=_("Distribute SVI interfaces over all switches")), - cfg.StrOpt('model_class', - default='neutron.plugins.cisco.models.virt_phy_sw_v2.' - 'VirtualPhysicalSwitchModelV2', - help=_("Model Class")), - cfg.StrOpt('nexus_driver', - default='neutron.plugins.cisco.test.nexus.' - 'fake_nexus_driver.CiscoNEXUSFakeDriver', - help=_("Nexus Driver Name")), -] - -cisco_n1k_opts = [ - cfg.StrOpt('integration_bridge', default='br-int', - help=_("N1K Integration Bridge")), - cfg.BoolOpt('enable_tunneling', default=True, - help=_("N1K Enable Tunneling")), - cfg.StrOpt('tunnel_bridge', default='br-tun', - help=_("N1K Tunnel Bridge")), - cfg.StrOpt('local_ip', default='10.0.0.3', - help=_("N1K Local IP")), - cfg.StrOpt('tenant_network_type', default='local', - help=_("N1K Tenant Network Type")), - cfg.StrOpt('bridge_mappings', default='', - help=_("N1K Bridge Mappings")), - cfg.StrOpt('vxlan_id_ranges', default='5000:10000', - help=_("N1K VXLAN ID Ranges")), - cfg.StrOpt('network_vlan_ranges', default='vlan:1:4095', - help=_("N1K Network VLAN Ranges")), - cfg.StrOpt('default_network_profile', default='default_network_profile', - help=_("N1K default network profile")), - cfg.StrOpt('default_policy_profile', default='service_profile', - help=_("N1K default policy profile")), - cfg.StrOpt('network_node_policy_profile', default='dhcp_pp', - help=_("N1K policy profile for network node")), - cfg.IntOpt('poll_duration', default=10, - help=_("N1K Policy profile polling duration in seconds")), - cfg.IntOpt('http_pool_size', default=4, - help=_("Number of threads to use to make HTTP requests")), -] - -cfg.CONF.register_opts(cisco_opts, "CISCO") -cfg.CONF.register_opts(cisco_n1k_opts, "CISCO_N1K") -cfg.CONF.register_opts(cisco_plugins_opts, "CISCO_PLUGINS") -config.register_root_helper(cfg.CONF) - -# shortcuts -CONF = cfg.CONF -CISCO = cfg.CONF.CISCO -CISCO_N1K = cfg.CONF.CISCO_N1K -CISCO_PLUGINS = cfg.CONF.CISCO_PLUGINS - -# -# device_dictionary - Contains all external device configuration. -# -# When populated the device dictionary format is: -# {('', '', ''): '', ...} -# -# Example: -# {('NEXUS_SWITCH', '1.1.1.1', 'username'): 'admin', -# ('NEXUS_SWITCH', '1.1.1.1', 'password'): 'mySecretPassword', -# ('NEXUS_SWITCH', '1.1.1.1', 'compute1'): '1/1', ...} -# -device_dictionary = {} - -# -# first_device_ip - IP address of first switch discovered in config -# -# Used for SVI placement when round-robin placement is disabled -# -first_device_ip = None - - -class CiscoConfigOptions(): - """Cisco Configuration Options Class.""" - - def __init__(self): - self._create_device_dictionary() - - def _create_device_dictionary(self): - """ - Create the device dictionary from the cisco_plugins.ini - device supported sections. Ex. NEXUS_SWITCH, N1KV. - """ - - global first_device_ip - - multi_parser = cfg.MultiConfigParser() - read_ok = multi_parser.read(CONF.config_file) - - if len(read_ok) != len(CONF.config_file): - raise cfg.Error(_("Some config files were not parsed properly")) - - first_device_ip = None - for parsed_file in multi_parser.parsed: - for parsed_item in parsed_file.keys(): - dev_id, sep, dev_ip = parsed_item.partition(':') - if dev_id.lower() in ['nexus_switch', 'n1kv']: - for dev_key, value in parsed_file[parsed_item].items(): - if dev_ip and not first_device_ip: - first_device_ip = dev_ip - device_dictionary[dev_id, dev_ip, dev_key] = value[0] - - -def get_device_dictionary(): - return device_dictionary diff --git a/neutron/plugins/cisco/db/__init__.py b/neutron/plugins/cisco/db/__init__.py deleted file mode 100644 index db695fb0a..000000000 --- a/neutron/plugins/cisco/db/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 Cisco Systems, Inc. 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: Sumit Naiksatam, Cisco Systems, Inc. -# diff --git a/neutron/plugins/cisco/db/n1kv_db_v2.py b/neutron/plugins/cisco/db/n1kv_db_v2.py deleted file mode 100644 index d924af9b3..000000000 --- a/neutron/plugins/cisco/db/n1kv_db_v2.py +++ /dev/null @@ -1,1621 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cisco Systems, Inc. -# -# 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: Aruna Kushwaha, Cisco Systems Inc. -# @author: Abhishek Raut, Cisco Systems Inc. -# @author: Rudrajit Tapadar, Cisco Systems Inc. -# @author: Sergey Sudakovich, Cisco Systems Inc. - -import netaddr -import re -from sqlalchemy.orm import exc -from sqlalchemy import sql - -from neutron.api.v2 import attributes -from neutron.common import constants -from neutron.common import exceptions as n_exc -import neutron.db.api as db -from neutron.db import models_v2 -from neutron.openstack.common import log as logging -from neutron.plugins.cisco.common import cisco_constants as c_const -from neutron.plugins.cisco.common import cisco_exceptions as c_exc -from neutron.plugins.cisco.db import n1kv_models_v2 - -LOG = logging.getLogger(__name__) - - -def del_trunk_segment_binding(db_session, trunk_segment_id, segment_pairs): - """ - Delete a trunk network binding. - - :param db_session: database session - :param trunk_segment_id: UUID representing the trunk network - :param segment_pairs: List of segment UUIDs in pair - representing the segments that are trunked - """ - with db_session.begin(subtransactions=True): - for (segment_id, dot1qtag) in segment_pairs: - (db_session.query(n1kv_models_v2.N1kvTrunkSegmentBinding). - filter_by(trunk_segment_id=trunk_segment_id, - segment_id=segment_id, - dot1qtag=dot1qtag).delete()) - alloc = (db_session.query(n1kv_models_v2. - N1kvTrunkSegmentBinding). - filter_by(trunk_segment_id=trunk_segment_id).first()) - if not alloc: - binding = get_network_binding(db_session, trunk_segment_id) - binding.physical_network = None - - -def del_multi_segment_binding(db_session, multi_segment_id, segment_pairs): - """ - Delete a multi-segment network binding. - - :param db_session: database session - :param multi_segment_id: UUID representing the multi-segment network - :param segment_pairs: List of segment UUIDs in pair - representing the segments that are bridged - """ - with db_session.begin(subtransactions=True): - for (segment1_id, segment2_id) in segment_pairs: - (db_session.query(n1kv_models_v2. - N1kvMultiSegmentNetworkBinding).filter_by( - multi_segment_id=multi_segment_id, - segment1_id=segment1_id, - segment2_id=segment2_id).delete()) - - -def add_trunk_segment_binding(db_session, trunk_segment_id, segment_pairs): - """ - Create a trunk network binding. - - :param db_session: database session - :param trunk_segment_id: UUID representing the multi-segment network - :param segment_pairs: List of segment UUIDs in pair - representing the segments to be trunked - """ - with db_session.begin(subtransactions=True): - binding = get_network_binding(db_session, trunk_segment_id) - for (segment_id, tag) in segment_pairs: - if not binding.physical_network: - member_seg_binding = get_network_binding(db_session, - segment_id) - binding.physical_network = member_seg_binding.physical_network - trunk_segment_binding = ( - n1kv_models_v2.N1kvTrunkSegmentBinding( - trunk_segment_id=trunk_segment_id, - segment_id=segment_id, dot1qtag=tag)) - db_session.add(trunk_segment_binding) - - -def add_multi_segment_binding(db_session, multi_segment_id, segment_pairs): - """ - Create a multi-segment network binding. - - :param db_session: database session - :param multi_segment_id: UUID representing the multi-segment network - :param segment_pairs: List of segment UUIDs in pair - representing the segments to be bridged - """ - with db_session.begin(subtransactions=True): - for (segment1_id, segment2_id) in segment_pairs: - multi_segment_binding = ( - n1kv_models_v2.N1kvMultiSegmentNetworkBinding( - multi_segment_id=multi_segment_id, - segment1_id=segment1_id, - segment2_id=segment2_id)) - db_session.add(multi_segment_binding) - - -def add_multi_segment_encap_profile_name(db_session, multi_segment_id, - segment_pair, profile_name): - """ - Add the encapsulation profile name to the multi-segment network binding. - - :param db_session: database session - :param multi_segment_id: UUID representing the multi-segment network - :param segment_pair: set containing the segment UUIDs that are bridged - """ - with db_session.begin(subtransactions=True): - binding = get_multi_segment_network_binding(db_session, - multi_segment_id, - segment_pair) - binding.encap_profile_name = profile_name - - -def get_multi_segment_network_binding(db_session, - multi_segment_id, segment_pair): - """ - Retrieve multi-segment network binding. - - :param db_session: database session - :param multi_segment_id: UUID representing the trunk network whose binding - is to fetch - :param segment_pair: set containing the segment UUIDs that are bridged - :returns: binding object - """ - try: - (segment1_id, segment2_id) = segment_pair - return (db_session.query( - n1kv_models_v2.N1kvMultiSegmentNetworkBinding). - filter_by(multi_segment_id=multi_segment_id, - segment1_id=segment1_id, - segment2_id=segment2_id)).one() - except exc.NoResultFound: - raise c_exc.NetworkBindingNotFound(network_id=multi_segment_id) - - -def get_multi_segment_members(db_session, multi_segment_id): - """ - Retrieve all the member segments of a multi-segment network. - - :param db_session: database session - :param multi_segment_id: UUID representing the multi-segment network - :returns: a list of tuples representing the mapped segments - """ - with db_session.begin(subtransactions=True): - allocs = (db_session.query( - n1kv_models_v2.N1kvMultiSegmentNetworkBinding). - filter_by(multi_segment_id=multi_segment_id)) - return [(a.segment1_id, a.segment2_id) for a in allocs] - - -def get_multi_segment_encap_dict(db_session, multi_segment_id): - """ - Retrieve the encapsulation profiles for every segment pairs bridged. - - :param db_session: database session - :param multi_segment_id: UUID representing the multi-segment network - :returns: a dictionary of lists containing the segment pairs in sets - """ - with db_session.begin(subtransactions=True): - encap_dict = {} - allocs = (db_session.query( - n1kv_models_v2.N1kvMultiSegmentNetworkBinding). - filter_by(multi_segment_id=multi_segment_id)) - for alloc in allocs: - if alloc.encap_profile_name not in encap_dict: - encap_dict[alloc.encap_profile_name] = [] - seg_pair = (alloc.segment1_id, alloc.segment2_id) - encap_dict[alloc.encap_profile_name].append(seg_pair) - return encap_dict - - -def get_trunk_network_binding(db_session, trunk_segment_id, segment_pair): - """ - Retrieve trunk network binding. - - :param db_session: database session - :param trunk_segment_id: UUID representing the trunk network whose binding - is to fetch - :param segment_pair: set containing the segment_id and dot1qtag - :returns: binding object - """ - try: - (segment_id, dot1qtag) = segment_pair - return (db_session.query(n1kv_models_v2.N1kvTrunkSegmentBinding). - filter_by(trunk_segment_id=trunk_segment_id, - segment_id=segment_id, - dot1qtag=dot1qtag)).one() - except exc.NoResultFound: - raise c_exc.NetworkBindingNotFound(network_id=trunk_segment_id) - - -def get_trunk_members(db_session, trunk_segment_id): - """ - Retrieve all the member segments of a trunk network. - - :param db_session: database session - :param trunk_segment_id: UUID representing the trunk network - :returns: a list of tuples representing the segment and their - corresponding dot1qtag - """ - with db_session.begin(subtransactions=True): - allocs = (db_session.query(n1kv_models_v2.N1kvTrunkSegmentBinding). - filter_by(trunk_segment_id=trunk_segment_id)) - return [(a.segment_id, a.dot1qtag) for a in allocs] - - -def is_trunk_member(db_session, segment_id): - """ - Checks if a segment is a member of a trunk segment. - - :param db_session: database session - :param segment_id: UUID of the segment to be checked - :returns: boolean - """ - with db_session.begin(subtransactions=True): - ret = (db_session.query(n1kv_models_v2.N1kvTrunkSegmentBinding). - filter_by(segment_id=segment_id).first()) - return bool(ret) - - -def is_multi_segment_member(db_session, segment_id): - """ - Checks if a segment is a member of a multi-segment network. - - :param db_session: database session - :param segment_id: UUID of the segment to be checked - :returns: boolean - """ - with db_session.begin(subtransactions=True): - ret1 = (db_session.query( - n1kv_models_v2.N1kvMultiSegmentNetworkBinding). - filter_by(segment1_id=segment_id).first()) - ret2 = (db_session.query( - n1kv_models_v2.N1kvMultiSegmentNetworkBinding). - filter_by(segment2_id=segment_id).first()) - return bool(ret1 or ret2) - - -def get_network_binding(db_session, network_id): - """ - Retrieve network binding. - - :param db_session: database session - :param network_id: UUID representing the network whose binding is - to fetch - :returns: binding object - """ - try: - return (db_session.query(n1kv_models_v2.N1kvNetworkBinding). - filter_by(network_id=network_id). - one()) - except exc.NoResultFound: - raise c_exc.NetworkBindingNotFound(network_id=network_id) - - -def add_network_binding(db_session, network_id, network_type, - physical_network, segmentation_id, - multicast_ip, network_profile_id, add_segments): - """ - Create network binding. - - :param db_session: database session - :param network_id: UUID representing the network - :param network_type: string representing type of network (VLAN, OVERLAY, - MULTI_SEGMENT or TRUNK) - :param physical_network: Only applicable for VLAN networks. It - represents a L2 Domain - :param segmentation_id: integer representing VLAN or VXLAN ID - :param multicast_ip: Native VXLAN technology needs a multicast IP to be - associated with every VXLAN ID to deal with broadcast - packets. A single multicast IP can be shared by - multiple VXLAN IDs. - :param network_profile_id: network profile ID based on which this network - is created - :param add_segments: List of segment UUIDs in pairs to be added to either a - multi-segment or trunk network - """ - with db_session.begin(subtransactions=True): - binding = n1kv_models_v2.N1kvNetworkBinding( - network_id=network_id, - network_type=network_type, - physical_network=physical_network, - segmentation_id=segmentation_id, - multicast_ip=multicast_ip, - profile_id=network_profile_id) - db_session.add(binding) - if add_segments is None: - pass - elif network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT: - add_multi_segment_binding(db_session, network_id, add_segments) - elif network_type == c_const.NETWORK_TYPE_TRUNK: - add_trunk_segment_binding(db_session, network_id, add_segments) - - -def get_segment_range(network_profile): - """ - Get the segment range min and max for a network profile. - - :params network_profile: object of type network profile - :returns: integer values representing minimum and maximum segment - range value - """ - # Sort the range to ensure min, max is in order - seg_min, seg_max = sorted( - int(i) for i in network_profile.segment_range.split('-')) - LOG.debug(_("seg_min %(seg_min)s, seg_max %(seg_max)s"), - {'seg_min': seg_min, 'seg_max': seg_max}) - return seg_min, seg_max - - -def get_multicast_ip(network_profile): - """ - Retrieve a multicast ip from the defined pool. - - :params network_profile: object of type network profile - :returns: string representing multicast IP - """ - # Round robin multicast ip allocation - min_ip, max_ip = _get_multicast_ip_range(network_profile) - addr_list = list((netaddr.iter_iprange(min_ip, max_ip))) - mul_ip_str = str(addr_list[network_profile.multicast_ip_index]) - - network_profile.multicast_ip_index += 1 - if network_profile.multicast_ip_index == len(addr_list): - network_profile.multicast_ip_index = 0 - return mul_ip_str - - -def _get_multicast_ip_range(network_profile): - """ - Helper method to retrieve minimum and maximum multicast ip. - - :params network_profile: object of type network profile - :returns: two strings representing minimum multicast ip and - maximum multicast ip - """ - # Assumption: ip range belongs to the same subnet - # Assumption: ip range is already sorted - return network_profile.multicast_ip_range.split('-') - - -def get_port_binding(db_session, port_id): - """ - Retrieve port binding. - - :param db_session: database session - :param port_id: UUID representing the port whose binding is to fetch - :returns: port binding object - """ - try: - return (db_session.query(n1kv_models_v2.N1kvPortBinding). - filter_by(port_id=port_id). - one()) - except exc.NoResultFound: - raise c_exc.PortBindingNotFound(port_id=port_id) - - -def add_port_binding(db_session, port_id, policy_profile_id): - """ - Create port binding. - - Bind the port with policy profile. - :param db_session: database session - :param port_id: UUID of the port - :param policy_profile_id: UUID of the policy profile - """ - with db_session.begin(subtransactions=True): - binding = n1kv_models_v2.N1kvPortBinding(port_id=port_id, - profile_id=policy_profile_id) - db_session.add(binding) - - -def delete_segment_allocations(db_session, net_p): - """ - Delete the segment allocation entry from the table. - - :params db_session: database session - :params net_p: network profile object - """ - with db_session.begin(subtransactions=True): - seg_min, seg_max = get_segment_range(net_p) - if net_p['segment_type'] == c_const.NETWORK_TYPE_VLAN: - db_session.query(n1kv_models_v2.N1kvVlanAllocation).filter( - (n1kv_models_v2.N1kvVlanAllocation.physical_network == - net_p['physical_network']), - (n1kv_models_v2.N1kvVlanAllocation.vlan_id >= seg_min), - (n1kv_models_v2.N1kvVlanAllocation.vlan_id <= - seg_max)).delete() - elif net_p['segment_type'] == c_const.NETWORK_TYPE_OVERLAY: - db_session.query(n1kv_models_v2.N1kvVxlanAllocation).filter( - (n1kv_models_v2.N1kvVxlanAllocation.vxlan_id >= seg_min), - (n1kv_models_v2.N1kvVxlanAllocation.vxlan_id <= - seg_max)).delete() - - -def sync_vlan_allocations(db_session, net_p): - """ - Synchronize vlan_allocations table with configured VLAN ranges. - - Sync the network profile range with the vlan_allocations table for each - physical network. - :param db_session: database session - :param net_p: network profile dictionary - """ - with db_session.begin(subtransactions=True): - seg_min, seg_max = get_segment_range(net_p) - for vlan_id in range(seg_min, seg_max + 1): - try: - get_vlan_allocation(db_session, - net_p['physical_network'], - vlan_id) - except c_exc.VlanIDNotFound: - alloc = n1kv_models_v2.N1kvVlanAllocation( - physical_network=net_p['physical_network'], - vlan_id=vlan_id, - network_profile_id=net_p['id']) - db_session.add(alloc) - - -def get_vlan_allocation(db_session, physical_network, vlan_id): - """ - Retrieve vlan allocation. - - :param db_session: database session - :param physical network: string name for the physical network - :param vlan_id: integer representing the VLAN ID. - :returns: allocation object for given physical network and VLAN ID - """ - try: - return (db_session.query(n1kv_models_v2.N1kvVlanAllocation). - filter_by(physical_network=physical_network, - vlan_id=vlan_id).one()) - except exc.NoResultFound: - raise c_exc.VlanIDNotFound(vlan_id=vlan_id) - - -def reserve_vlan(db_session, network_profile): - """ - Reserve a VLAN ID within the range of the network profile. - - :param db_session: database session - :param network_profile: network profile object - """ - seg_min, seg_max = get_segment_range(network_profile) - segment_type = c_const.NETWORK_TYPE_VLAN - - with db_session.begin(subtransactions=True): - alloc = (db_session.query(n1kv_models_v2.N1kvVlanAllocation). - filter(sql.and_( - n1kv_models_v2.N1kvVlanAllocation.vlan_id >= seg_min, - n1kv_models_v2.N1kvVlanAllocation.vlan_id <= seg_max, - n1kv_models_v2.N1kvVlanAllocation.physical_network == - network_profile['physical_network'], - n1kv_models_v2.N1kvVlanAllocation.allocated == - sql.false()) - )).first() - if alloc: - segment_id = alloc.vlan_id - physical_network = alloc.physical_network - alloc.allocated = True - return (physical_network, segment_type, segment_id, "0.0.0.0") - raise c_exc.NoMoreNetworkSegments( - network_profile_name=network_profile.name) - - -def reserve_vxlan(db_session, network_profile): - """ - Reserve a VXLAN ID within the range of the network profile. - - :param db_session: database session - :param network_profile: network profile object - """ - seg_min, seg_max = get_segment_range(network_profile) - segment_type = c_const.NETWORK_TYPE_OVERLAY - physical_network = "" - - with db_session.begin(subtransactions=True): - alloc = (db_session.query(n1kv_models_v2.N1kvVxlanAllocation). - filter(sql.and_( - n1kv_models_v2.N1kvVxlanAllocation.vxlan_id >= - seg_min, - n1kv_models_v2.N1kvVxlanAllocation.vxlan_id <= - seg_max, - n1kv_models_v2.N1kvVxlanAllocation.allocated == - sql.false()) - ).first()) - if alloc: - segment_id = alloc.vxlan_id - alloc.allocated = True - if network_profile.sub_type == (c_const. - NETWORK_SUBTYPE_NATIVE_VXLAN): - return (physical_network, segment_type, - segment_id, get_multicast_ip(network_profile)) - else: - return (physical_network, segment_type, segment_id, "0.0.0.0") - raise n_exc.NoNetworkAvailable() - - -def alloc_network(db_session, network_profile_id): - """ - Allocate network using first available free segment ID in segment range. - - :param db_session: database session - :param network_profile_id: UUID representing the network profile - """ - with db_session.begin(subtransactions=True): - network_profile = get_network_profile(db_session, - network_profile_id) - if network_profile.segment_type == c_const.NETWORK_TYPE_VLAN: - return reserve_vlan(db_session, network_profile) - if network_profile.segment_type == c_const.NETWORK_TYPE_OVERLAY: - return reserve_vxlan(db_session, network_profile) - return (None, network_profile.segment_type, 0, "0.0.0.0") - - -def reserve_specific_vlan(db_session, physical_network, vlan_id): - """ - Reserve a specific VLAN ID for the network. - - :param db_session: database session - :param physical_network: string representing the name of physical network - :param vlan_id: integer value of the segmentation ID to be reserved - """ - with db_session.begin(subtransactions=True): - try: - alloc = (db_session.query(n1kv_models_v2.N1kvVlanAllocation). - filter_by(physical_network=physical_network, - vlan_id=vlan_id). - one()) - if alloc.allocated: - if vlan_id == c_const.FLAT_VLAN_ID: - raise n_exc.FlatNetworkInUse( - physical_network=physical_network) - else: - raise n_exc.VlanIdInUse(vlan_id=vlan_id, - physical_network=physical_network) - LOG.debug(_("Reserving specific vlan %(vlan)s on physical " - "network %(network)s from pool"), - {"vlan": vlan_id, "network": physical_network}) - alloc.allocated = True - db_session.add(alloc) - except exc.NoResultFound: - raise c_exc.VlanIDOutsidePool - - -def release_vlan(db_session, physical_network, vlan_id): - """ - Release a given VLAN ID. - - :param db_session: database session - :param physical_network: string representing the name of physical network - :param vlan_id: integer value of the segmentation ID to be released - """ - with db_session.begin(subtransactions=True): - try: - alloc = (db_session.query(n1kv_models_v2.N1kvVlanAllocation). - filter_by(physical_network=physical_network, - vlan_id=vlan_id). - one()) - alloc.allocated = False - except exc.NoResultFound: - LOG.warning(_("vlan_id %(vlan)s on physical network %(network)s " - "not found"), - {"vlan": vlan_id, "network": physical_network}) - - -def sync_vxlan_allocations(db_session, net_p): - """ - Synchronize vxlan_allocations table with configured vxlan ranges. - - :param db_session: database session - :param net_p: network profile dictionary - """ - seg_min, seg_max = get_segment_range(net_p) - if seg_max + 1 - seg_min > c_const.MAX_VXLAN_RANGE: - msg = (_("Unreasonable vxlan ID range %(vxlan_min)s - %(vxlan_max)s"), - {"vxlan_min": seg_min, "vxlan_max": seg_max}) - raise n_exc.InvalidInput(error_message=msg) - with db_session.begin(subtransactions=True): - for vxlan_id in range(seg_min, seg_max + 1): - try: - get_vxlan_allocation(db_session, vxlan_id) - except c_exc.VxlanIDNotFound: - alloc = n1kv_models_v2.N1kvVxlanAllocation( - network_profile_id=net_p['id'], vxlan_id=vxlan_id) - db_session.add(alloc) - - -def get_vxlan_allocation(db_session, vxlan_id): - """ - Retrieve VXLAN allocation for the given VXLAN ID. - - :param db_session: database session - :param vxlan_id: integer value representing the segmentation ID - :returns: allocation object - """ - try: - return (db_session.query(n1kv_models_v2.N1kvVxlanAllocation). - filter_by(vxlan_id=vxlan_id).one()) - except exc.NoResultFound: - raise c_exc.VxlanIDNotFound(vxlan_id=vxlan_id) - - -def reserve_specific_vxlan(db_session, vxlan_id): - """ - Reserve a specific VXLAN ID. - - :param db_session: database session - :param vxlan_id: integer value representing the segmentation ID - """ - with db_session.begin(subtransactions=True): - try: - alloc = (db_session.query(n1kv_models_v2.N1kvVxlanAllocation). - filter_by(vxlan_id=vxlan_id). - one()) - if alloc.allocated: - raise c_exc.VxlanIDInUse(vxlan_id=vxlan_id) - LOG.debug(_("Reserving specific vxlan %s from pool"), vxlan_id) - alloc.allocated = True - db_session.add(alloc) - except exc.NoResultFound: - raise c_exc.VxlanIDOutsidePool - - -def release_vxlan(db_session, vxlan_id): - """ - Release a given VXLAN ID. - - :param db_session: database session - :param vxlan_id: integer value representing the segmentation ID - """ - with db_session.begin(subtransactions=True): - try: - alloc = (db_session.query(n1kv_models_v2.N1kvVxlanAllocation). - filter_by(vxlan_id=vxlan_id). - one()) - alloc.allocated = False - except exc.NoResultFound: - LOG.warning(_("vxlan_id %s not found"), vxlan_id) - - -def set_port_status(port_id, status): - """ - Set the status of the port. - - :param port_id: UUID representing the port - :param status: string representing the new status - """ - db_session = db.get_session() - try: - port = db_session.query(models_v2.Port).filter_by(id=port_id).one() - port.status = status - except exc.NoResultFound: - raise n_exc.PortNotFound(port_id=port_id) - - -def get_vm_network(db_session, policy_profile_id, network_id): - """ - Retrieve a vm_network based on policy profile and network id. - - :param db_session: database session - :param policy_profile_id: UUID representing policy profile - :param network_id: UUID representing network - :returns: VM network object - """ - try: - return (db_session.query(n1kv_models_v2.N1kVmNetwork). - filter_by(profile_id=policy_profile_id, - network_id=network_id).one()) - except exc.NoResultFound: - name = (c_const.VM_NETWORK_NAME_PREFIX + policy_profile_id - + "_" + network_id) - raise c_exc.VMNetworkNotFound(name=name) - - -def add_vm_network(db_session, - name, - policy_profile_id, - network_id, - port_count): - """ - Create a VM network. - - Add a VM network for a unique combination of network and - policy profile. All ports having the same policy profile - on one network will be associated with one VM network. - :param db_session: database session - :param name: string representing the name of the VM network - :param policy_profile_id: UUID representing policy profile - :param network_id: UUID representing a network - :param port_count: integer representing the number of ports on vm network - """ - with db_session.begin(subtransactions=True): - vm_network = n1kv_models_v2.N1kVmNetwork( - name=name, - profile_id=policy_profile_id, - network_id=network_id, - port_count=port_count) - db_session.add(vm_network) - - -def update_vm_network_port_count(db_session, name, port_count): - """ - Update a VM network with new port count. - - :param db_session: database session - :param name: string representing the name of the VM network - :param port_count: integer representing the number of ports on VM network - """ - try: - with db_session.begin(subtransactions=True): - vm_network = (db_session.query(n1kv_models_v2.N1kVmNetwork). - filter_by(name=name).one()) - if port_count is not None: - vm_network.port_count = port_count - return vm_network - except exc.NoResultFound: - raise c_exc.VMNetworkNotFound(name=name) - - -def delete_vm_network(db_session, policy_profile_id, network_id): - """ - Delete a VM network. - - :param db_session: database session - :param policy_profile_id: UUID representing a policy profile - :param network_id: UUID representing a network - :returns: deleted VM network object - """ - with db_session.begin(subtransactions=True): - try: - vm_network = get_vm_network(db_session, - policy_profile_id, - network_id) - db_session.delete(vm_network) - db_session.query(n1kv_models_v2.N1kVmNetwork).filter_by( - name=vm_network["name"]).delete() - return vm_network - except exc.NoResultFound: - name = (c_const.VM_NETWORK_NAME_PREFIX + policy_profile_id + - "_" + network_id) - raise c_exc.VMNetworkNotFound(name=name) - - -def create_network_profile(db_session, network_profile): - """Create a network profile.""" - LOG.debug(_("create_network_profile()")) - with db_session.begin(subtransactions=True): - kwargs = {"name": network_profile["name"], - "segment_type": network_profile["segment_type"]} - if network_profile["segment_type"] == c_const.NETWORK_TYPE_VLAN: - kwargs["physical_network"] = network_profile["physical_network"] - kwargs["segment_range"] = network_profile["segment_range"] - elif network_profile["segment_type"] == c_const.NETWORK_TYPE_OVERLAY: - kwargs["multicast_ip_index"] = 0 - kwargs["multicast_ip_range"] = network_profile[ - "multicast_ip_range"] - kwargs["segment_range"] = network_profile["segment_range"] - kwargs["sub_type"] = network_profile["sub_type"] - elif network_profile["segment_type"] == c_const.NETWORK_TYPE_TRUNK: - kwargs["sub_type"] = network_profile["sub_type"] - net_profile = n1kv_models_v2.NetworkProfile(**kwargs) - db_session.add(net_profile) - return net_profile - - -def delete_network_profile(db_session, id): - """Delete Network Profile.""" - LOG.debug(_("delete_network_profile()")) - with db_session.begin(subtransactions=True): - try: - network_profile = get_network_profile(db_session, id) - db_session.delete(network_profile) - (db_session.query(n1kv_models_v2.ProfileBinding). - filter_by(profile_id=id).delete()) - return network_profile - except exc.NoResultFound: - raise c_exc.ProfileTenantBindingNotFound(profile_id=id) - - -def update_network_profile(db_session, id, network_profile): - """Update Network Profile.""" - LOG.debug(_("update_network_profile()")) - with db_session.begin(subtransactions=True): - profile = get_network_profile(db_session, id) - profile.update(network_profile) - return profile - - -def get_network_profile(db_session, id): - """Get Network Profile.""" - LOG.debug(_("get_network_profile()")) - try: - return db_session.query( - n1kv_models_v2.NetworkProfile).filter_by(id=id).one() - except exc.NoResultFound: - raise c_exc.NetworkProfileNotFound(profile=id) - - -def _get_network_profiles(db_session=None, physical_network=None): - """ - Retrieve all network profiles. - - Get Network Profiles on a particular physical network, if physical - network is specified. If no physical network is specified, return - all network profiles. - """ - db_session = db_session or db.get_session() - if physical_network: - return (db_session.query(n1kv_models_v2.NetworkProfile). - filter_by(physical_network=physical_network)) - return db_session.query(n1kv_models_v2.NetworkProfile) - - -def create_policy_profile(policy_profile): - """Create Policy Profile.""" - LOG.debug(_("create_policy_profile()")) - db_session = db.get_session() - with db_session.begin(subtransactions=True): - p_profile = n1kv_models_v2.PolicyProfile(id=policy_profile["id"], - name=policy_profile["name"]) - db_session.add(p_profile) - return p_profile - - -def delete_policy_profile(id): - """Delete Policy Profile.""" - LOG.debug(_("delete_policy_profile()")) - db_session = db.get_session() - with db_session.begin(subtransactions=True): - policy_profile = get_policy_profile(db_session, id) - db_session.delete(policy_profile) - - -def update_policy_profile(db_session, id, policy_profile): - """Update a policy profile.""" - LOG.debug(_("update_policy_profile()")) - with db_session.begin(subtransactions=True): - _profile = get_policy_profile(db_session, id) - _profile.update(policy_profile) - return _profile - - -def get_policy_profile(db_session, id): - """Get Policy Profile.""" - LOG.debug(_("get_policy_profile()")) - try: - return db_session.query( - n1kv_models_v2.PolicyProfile).filter_by(id=id).one() - except exc.NoResultFound: - raise c_exc.PolicyProfileIdNotFound(profile_id=id) - - -def get_policy_profiles(): - """Retrieve all policy profiles.""" - db_session = db.get_session() - with db_session.begin(subtransactions=True): - return db_session.query(n1kv_models_v2.PolicyProfile) - - -def create_profile_binding(db_session, tenant_id, profile_id, profile_type): - """Create Network/Policy Profile association with a tenant.""" - db_session = db_session or db.get_session() - if profile_type not in ["network", "policy"]: - raise n_exc.NeutronException(_("Invalid profile type")) - - if _profile_binding_exists(db_session, - tenant_id, - profile_id, - profile_type): - return get_profile_binding(db_session, tenant_id, profile_id) - - with db_session.begin(subtransactions=True): - binding = n1kv_models_v2.ProfileBinding(profile_type=profile_type, - profile_id=profile_id, - tenant_id=tenant_id) - db_session.add(binding) - return binding - - -def _profile_binding_exists(db_session, tenant_id, profile_id, profile_type): - LOG.debug(_("_profile_binding_exists()")) - return (db_session.query(n1kv_models_v2.ProfileBinding). - filter_by(tenant_id=tenant_id, profile_id=profile_id, - profile_type=profile_type).first()) - - -def get_profile_binding(db_session, tenant_id, profile_id): - """Get Network/Policy Profile - Tenant binding.""" - LOG.debug(_("get_profile_binding()")) - try: - return (db_session.query(n1kv_models_v2.ProfileBinding).filter_by( - tenant_id=tenant_id, profile_id=profile_id).one()) - except exc.NoResultFound: - raise c_exc.ProfileTenantBindingNotFound(profile_id=profile_id) - - -def delete_profile_binding(db_session, tenant_id, profile_id): - """Delete Policy Binding.""" - LOG.debug(_("delete_profile_binding()")) - db_session = db_session or db.get_session() - try: - binding = get_profile_binding(db_session, tenant_id, profile_id) - with db_session.begin(subtransactions=True): - db_session.delete(binding) - except c_exc.ProfileTenantBindingNotFound: - LOG.debug(_("Profile-Tenant binding missing for profile ID " - "%(profile_id)s and tenant ID %(tenant_id)s"), - {"profile_id": profile_id, "tenant_id": tenant_id}) - return - - -def _get_profile_bindings(db_session, profile_type=None): - """ - Retrieve a list of profile bindings. - - Get all profile-tenant bindings based on profile type. - If profile type is None, return profile-tenant binding for all - profile types. - """ - LOG.debug(_("_get_profile_bindings()")) - if profile_type: - profile_bindings = (db_session.query(n1kv_models_v2.ProfileBinding). - filter_by(profile_type=profile_type)) - return profile_bindings - return db_session.query(n1kv_models_v2.ProfileBinding) - - -class NetworkProfile_db_mixin(object): - - """Network Profile Mixin.""" - - def _replace_fake_tenant_id_with_real(self, context): - """ - Replace default tenant-id with admin tenant-ids. - - Default tenant-ids are populated in profile bindings when plugin is - initialized. Replace these tenant-ids with admin's tenant-id. - :param context: neutron api request context - """ - if context.is_admin and context.tenant_id: - tenant_id = context.tenant_id - db_session = context.session - with db_session.begin(subtransactions=True): - (db_session.query(n1kv_models_v2.ProfileBinding). - filter_by(tenant_id=c_const.TENANT_ID_NOT_SET). - update({'tenant_id': tenant_id})) - - def _get_network_collection_for_tenant(self, db_session, model, tenant_id): - net_profile_ids = (db_session.query(n1kv_models_v2.ProfileBinding. - profile_id). - filter_by(tenant_id=tenant_id). - filter_by(profile_type=c_const.NETWORK)) - network_profiles = (db_session.query(model).filter(model.id.in_( - pid[0] for pid in net_profile_ids))) - return [self._make_network_profile_dict(p) for p in network_profiles] - - def _make_profile_bindings_dict(self, profile_binding, fields=None): - res = {"profile_id": profile_binding["profile_id"], - "tenant_id": profile_binding["tenant_id"]} - return self._fields(res, fields) - - def _make_network_profile_dict(self, network_profile, fields=None): - res = {"id": network_profile["id"], - "name": network_profile["name"], - "segment_type": network_profile["segment_type"], - "sub_type": network_profile["sub_type"], - "segment_range": network_profile["segment_range"], - "multicast_ip_index": network_profile["multicast_ip_index"], - "multicast_ip_range": network_profile["multicast_ip_range"], - "physical_network": network_profile["physical_network"]} - return self._fields(res, fields) - - def _segment_in_use(self, db_session, network_profile): - """Verify whether a segment is allocated for given network profile.""" - with db_session.begin(subtransactions=True): - return (db_session.query(n1kv_models_v2.N1kvNetworkBinding). - filter_by(profile_id=network_profile['id'])).first() - - def get_network_profile_bindings(self, context, filters=None, fields=None): - """ - Retrieve a list of profile bindings for network profiles. - - :param context: neutron api request context - :param filters: a dictionary with keys that are valid keys for a - profile bindings object. Values in this dictiontary are - an iterable containing values that will be used for an - exact match comparison for that value. Each result - returned by this function will have matched one of the - values for each key in filters - :params fields: a list of strings that are valid keys in a profile - bindings dictionary. Only these fields will be returned - :returns: list of profile bindings - """ - if context.is_admin: - profile_bindings = _get_profile_bindings( - context.session, - profile_type=c_const.NETWORK) - return [self._make_profile_bindings_dict(pb) - for pb in profile_bindings] - - def create_network_profile(self, context, network_profile): - """ - Create a network profile. - - :param context: neutron api request context - :param network_profile: network profile dictionary - :returns: network profile dictionary - """ - self._replace_fake_tenant_id_with_real(context) - p = network_profile["network_profile"] - self._validate_network_profile_args(context, p) - with context.session.begin(subtransactions=True): - net_profile = create_network_profile(context.session, p) - if net_profile.segment_type == c_const.NETWORK_TYPE_VLAN: - sync_vlan_allocations(context.session, net_profile) - elif net_profile.segment_type == c_const.NETWORK_TYPE_OVERLAY: - sync_vxlan_allocations(context.session, net_profile) - create_profile_binding(context.session, - context.tenant_id, - net_profile.id, - c_const.NETWORK) - if p.get("add_tenant"): - self.add_network_profile_tenant(context.session, - net_profile.id, - p["add_tenant"]) - return self._make_network_profile_dict(net_profile) - - def delete_network_profile(self, context, id): - """ - Delete a network profile. - - :param context: neutron api request context - :param id: UUID representing network profile to delete - :returns: deleted network profile dictionary - """ - # Check whether the network profile is in use. - if self._segment_in_use(context.session, - get_network_profile(context.session, id)): - raise c_exc.NetworkProfileInUse(profile=id) - # Delete and return the network profile if it is not in use. - _profile = delete_network_profile(context.session, id) - return self._make_network_profile_dict(_profile) - - def update_network_profile(self, context, id, network_profile): - """ - Update a network profile. - - Add/remove network profile to tenant-id binding for the corresponding - options and if user is admin. - :param context: neutron api request context - :param id: UUID representing network profile to update - :param network_profile: network profile dictionary - :returns: updated network profile dictionary - """ - # Flag to check whether network profile is updated or not. - is_updated = False - p = network_profile["network_profile"] - original_net_p = get_network_profile(context.session, id) - # Update network profile to tenant id binding. - if context.is_admin and "add_tenant" in p: - self.add_network_profile_tenant(context.session, id, - p["add_tenant"]) - is_updated = True - if context.is_admin and "remove_tenant" in p: - delete_profile_binding(context.session, p["remove_tenant"], id) - is_updated = True - if original_net_p.segment_type == c_const.NETWORK_TYPE_TRUNK: - #TODO(abhraut): Remove check when Trunk supports segment range. - if p.get('segment_range'): - msg = _("segment_range not required for TRUNK") - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - if original_net_p.segment_type in [c_const.NETWORK_TYPE_VLAN, - c_const.NETWORK_TYPE_TRUNK]: - if p.get("multicast_ip_range"): - msg = _("multicast_ip_range not required") - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - # Update segment range if network profile is not in use. - if (p.get("segment_range") and - p.get("segment_range") != original_net_p.segment_range): - if not self._segment_in_use(context.session, original_net_p): - delete_segment_allocations(context.session, original_net_p) - updated_net_p = update_network_profile(context.session, id, p) - self._validate_segment_range_uniqueness(context, - updated_net_p, id) - if original_net_p.segment_type == c_const.NETWORK_TYPE_VLAN: - sync_vlan_allocations(context.session, updated_net_p) - if original_net_p.segment_type == c_const.NETWORK_TYPE_OVERLAY: - sync_vxlan_allocations(context.session, updated_net_p) - is_updated = True - else: - raise c_exc.NetworkProfileInUse(profile=id) - if (p.get('multicast_ip_range') and - (p.get("multicast_ip_range") != - original_net_p.get("multicast_ip_range"))): - self._validate_multicast_ip_range(p) - if not self._segment_in_use(context.session, original_net_p): - is_updated = True - else: - raise c_exc.NetworkProfileInUse(profile=id) - # Update network profile if name is updated and the network profile - # is not yet updated. - if "name" in p and not is_updated: - is_updated = True - # Return network profile if it is successfully updated. - if is_updated: - return self._make_network_profile_dict( - update_network_profile(context.session, id, p)) - - def get_network_profile(self, context, id, fields=None): - """ - Retrieve a network profile. - - :param context: neutron api request context - :param id: UUID representing the network profile to retrieve - :params fields: a list of strings that are valid keys in a network - profile dictionary. Only these fields will be returned - :returns: network profile dictionary - """ - profile = get_network_profile(context.session, id) - return self._make_network_profile_dict(profile, fields) - - def get_network_profiles(self, context, filters=None, fields=None): - """ - Retrieve a list of all network profiles. - - Retrieve all network profiles if tenant is admin. For a non-admin - tenant, retrieve all network profiles belonging to this tenant only. - :param context: neutron api request context - :param filters: a dictionary with keys that are valid keys for a - network profile object. Values in this dictiontary are - an iterable containing values that will be used for an - exact match comparison for that value. Each result - returned by this function will have matched one of the - values for each key in filters - :params fields: a list of strings that are valid keys in a network - profile dictionary. Only these fields will be returned - :returns: list of all network profiles - """ - if context.is_admin: - return self._get_collection(context, n1kv_models_v2.NetworkProfile, - self._make_network_profile_dict, - filters=filters, fields=fields) - return self._get_network_collection_for_tenant(context.session, - n1kv_models_v2. - NetworkProfile, - context.tenant_id) - - def add_network_profile_tenant(self, - db_session, - network_profile_id, - tenant_id): - """ - Add a tenant to a network profile. - - :param db_session: database session - :param network_profile_id: UUID representing network profile - :param tenant_id: UUID representing the tenant - :returns: profile binding object - """ - return create_profile_binding(db_session, - tenant_id, - network_profile_id, - c_const.NETWORK) - - def network_profile_exists(self, context, id): - """ - Verify whether a network profile for given id exists. - - :param context: neutron api request context - :param id: UUID representing network profile - :returns: true if network profile exist else False - """ - try: - get_network_profile(context.session, id) - return True - except c_exc.NetworkProfileNotFound(profile=id): - return False - - def _get_segment_range(self, data): - return (int(seg) for seg in data.split("-")[:2]) - - def _validate_network_profile_args(self, context, p): - """ - Validate completeness of Nexus1000V network profile arguments. - - :param context: neutron api request context - :param p: network profile object - """ - self._validate_network_profile(p) - segment_type = p['segment_type'].lower() - if segment_type != c_const.NETWORK_TYPE_TRUNK: - self._validate_segment_range_uniqueness(context, p) - - def _validate_segment_range(self, network_profile): - """ - Validate segment range values. - - :param network_profile: network profile object - """ - if not re.match(r"(\d+)\-(\d+)", network_profile["segment_range"]): - msg = _("Invalid segment range. example range: 500-550") - raise n_exc.InvalidInput(error_message=msg) - - def _validate_multicast_ip_range(self, network_profile): - """ - Validate multicast ip range values. - - :param network_profile: network profile object - """ - try: - min_ip, max_ip = (network_profile - ['multicast_ip_range'].split('-', 1)) - except ValueError: - msg = _("Invalid multicast ip address range. " - "example range: 224.1.1.1-224.1.1.10") - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - for ip in [min_ip, max_ip]: - try: - if not netaddr.IPAddress(ip).is_multicast(): - msg = _("%s is not a valid multicast ip address") % ip - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - if netaddr.IPAddress(ip) <= netaddr.IPAddress('224.0.0.255'): - msg = _("%s is reserved multicast ip address") % ip - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - except netaddr.AddrFormatError: - msg = _("%s is not a valid ip address") % ip - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - if netaddr.IPAddress(min_ip) > netaddr.IPAddress(max_ip): - msg = (_("Invalid multicast IP range '%(min_ip)s-%(max_ip)s':" - " Range should be from low address to high address") % - {'min_ip': min_ip, 'max_ip': max_ip}) - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - - def _validate_network_profile(self, net_p): - """ - Validate completeness of a network profile arguments. - - :param net_p: network profile object - """ - if any(net_p[arg] == "" for arg in ["segment_type"]): - msg = _("Arguments segment_type missing" - " for network profile") - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - segment_type = net_p["segment_type"].lower() - if segment_type not in [c_const.NETWORK_TYPE_VLAN, - c_const.NETWORK_TYPE_OVERLAY, - c_const.NETWORK_TYPE_TRUNK, - c_const.NETWORK_TYPE_MULTI_SEGMENT]: - msg = _("segment_type should either be vlan, overlay, " - "multi-segment or trunk") - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - if segment_type == c_const.NETWORK_TYPE_VLAN: - if "physical_network" not in net_p: - msg = _("Argument physical_network missing " - "for network profile") - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - if segment_type == c_const.NETWORK_TYPE_TRUNK: - if net_p["segment_range"]: - msg = _("segment_range not required for trunk") - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - if segment_type in [c_const.NETWORK_TYPE_TRUNK, - c_const.NETWORK_TYPE_OVERLAY]: - if not attributes.is_attr_set(net_p.get("sub_type")): - msg = _("Argument sub_type missing " - "for network profile") - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - if segment_type in [c_const.NETWORK_TYPE_VLAN, - c_const.NETWORK_TYPE_OVERLAY]: - if "segment_range" not in net_p: - msg = _("Argument segment_range missing " - "for network profile") - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - self._validate_segment_range(net_p) - if segment_type == c_const.NETWORK_TYPE_OVERLAY: - if net_p['sub_type'] != c_const.NETWORK_SUBTYPE_NATIVE_VXLAN: - net_p['multicast_ip_range'] = '0.0.0.0' - else: - multicast_ip_range = net_p.get("multicast_ip_range") - if not attributes.is_attr_set(multicast_ip_range): - msg = _("Argument multicast_ip_range missing" - " for VXLAN multicast network profile") - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - self._validate_multicast_ip_range(net_p) - else: - net_p['multicast_ip_range'] = '0.0.0.0' - - def _validate_segment_range_uniqueness(self, context, net_p, id=None): - """ - Validate that segment range doesn't overlap. - - :param context: neutron api request context - :param net_p: network profile dictionary - :param id: UUID representing the network profile being updated - """ - segment_type = net_p["segment_type"].lower() - seg_min, seg_max = self._get_segment_range(net_p['segment_range']) - if segment_type == c_const.NETWORK_TYPE_VLAN: - if not ((seg_min <= seg_max) and - ((seg_min in range(constants.MIN_VLAN_TAG, - c_const.NEXUS_VLAN_RESERVED_MIN) and - seg_max in range(constants.MIN_VLAN_TAG, - c_const.NEXUS_VLAN_RESERVED_MIN)) or - (seg_min in range(c_const.NEXUS_VLAN_RESERVED_MAX + 1, - constants.MAX_VLAN_TAG) and - seg_max in range(c_const.NEXUS_VLAN_RESERVED_MAX + 1, - constants.MAX_VLAN_TAG)))): - msg = (_("Segment range is invalid, select from " - "%(min)s-%(nmin)s, %(nmax)s-%(max)s") % - {"min": constants.MIN_VLAN_TAG, - "nmin": c_const.NEXUS_VLAN_RESERVED_MIN - 1, - "nmax": c_const.NEXUS_VLAN_RESERVED_MAX + 1, - "max": constants.MAX_VLAN_TAG - 1}) - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - profiles = _get_network_profiles( - db_session=context.session, - physical_network=net_p["physical_network"] - ) - elif segment_type in [c_const.NETWORK_TYPE_OVERLAY, - c_const.NETWORK_TYPE_MULTI_SEGMENT, - c_const.NETWORK_TYPE_TRUNK]: - if (seg_min > seg_max or - seg_min < c_const.NEXUS_VXLAN_MIN or - seg_max > c_const.NEXUS_VXLAN_MAX): - msg = (_("segment range is invalid. Valid range is : " - "%(min)s-%(max)s") % - {"min": c_const.NEXUS_VXLAN_MIN, - "max": c_const.NEXUS_VXLAN_MAX}) - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - profiles = _get_network_profiles(db_session=context.session) - if profiles: - for profile in profiles: - if id and profile.id == id: - continue - name = profile.name - segment_range = profile.segment_range - if net_p["name"] == name: - msg = (_("NetworkProfile name %s already exists"), - net_p["name"]) - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - if (c_const.NETWORK_TYPE_MULTI_SEGMENT in - [profile.segment_type, net_p["segment_type"]] or - c_const.NETWORK_TYPE_TRUNK in - [profile.segment_type, net_p["segment_type"]]): - continue - seg_min, seg_max = self._get_segment_range( - net_p["segment_range"]) - profile_seg_min, profile_seg_max = self._get_segment_range( - segment_range) - if ((profile_seg_min <= seg_min <= profile_seg_max) or - (profile_seg_min <= seg_max <= profile_seg_max) or - ((seg_min <= profile_seg_min) and - (seg_max >= profile_seg_max))): - msg = _("Segment range overlaps with another profile") - LOG.error(msg) - raise n_exc.InvalidInput(error_message=msg) - - def _get_network_profile_by_name(self, db_session, name): - """ - Retrieve network profile based on name. - - :param db_session: database session - :param name: string representing the name for the network profile - :returns: network profile object - """ - with db_session.begin(subtransactions=True): - try: - return (db_session.query(n1kv_models_v2.NetworkProfile). - filter_by(name=name).one()) - except exc.NoResultFound: - raise c_exc.NetworkProfileNotFound(profile=name) - - -class PolicyProfile_db_mixin(object): - - """Policy Profile Mixin.""" - - def _get_policy_collection_for_tenant(self, db_session, model, tenant_id): - profile_ids = (db_session.query(n1kv_models_v2. - ProfileBinding.profile_id) - .filter_by(tenant_id=tenant_id). - filter_by(profile_type=c_const.POLICY).all()) - profiles = db_session.query(model).filter(model.id.in_( - pid[0] for pid in profile_ids)) - return [self._make_policy_profile_dict(p) for p in profiles] - - def _make_policy_profile_dict(self, policy_profile, fields=None): - res = {"id": policy_profile["id"], "name": policy_profile["name"]} - return self._fields(res, fields) - - def _make_profile_bindings_dict(self, profile_binding, fields=None): - res = {"profile_id": profile_binding["profile_id"], - "tenant_id": profile_binding["tenant_id"]} - return self._fields(res, fields) - - def _policy_profile_exists(self, id): - db_session = db.get_session() - return (db_session.query(n1kv_models_v2.PolicyProfile). - filter_by(id=id).first()) - - def get_policy_profile(self, context, id, fields=None): - """ - Retrieve a policy profile for the given UUID. - - :param context: neutron api request context - :param id: UUID representing policy profile to fetch - :params fields: a list of strings that are valid keys in a policy - profile dictionary. Only these fields will be returned - :returns: policy profile dictionary - """ - profile = get_policy_profile(context.session, id) - return self._make_policy_profile_dict(profile, fields) - - def get_policy_profiles(self, context, filters=None, fields=None): - """ - Retrieve a list of policy profiles. - - Retrieve all policy profiles if tenant is admin. For a non-admin - tenant, retrieve all policy profiles belonging to this tenant only. - :param context: neutron api request context - :param filters: a dictionary with keys that are valid keys for a - policy profile object. Values in this dictiontary are - an iterable containing values that will be used for an - exact match comparison for that value. Each result - returned by this function will have matched one of the - values for each key in filters - :params fields: a list of strings that are valid keys in a policy - profile dictionary. Only these fields will be returned - :returns: list of all policy profiles - """ - if context.is_admin: - return self._get_collection(context, n1kv_models_v2.PolicyProfile, - self._make_policy_profile_dict, - filters=filters, fields=fields) - else: - return self._get_policy_collection_for_tenant(context.session, - n1kv_models_v2. - PolicyProfile, - context.tenant_id) - - def get_policy_profile_bindings(self, context, filters=None, fields=None): - """ - Retrieve a list of profile bindings for policy profiles. - - :param context: neutron api request context - :param filters: a dictionary with keys that are valid keys for a - profile bindings object. Values in this dictiontary are - an iterable containing values that will be used for an - exact match comparison for that value. Each result - returned by this function will have matched one of the - values for each key in filters - :params fields: a list of strings that are valid keys in a profile - bindings dictionary. Only these fields will be returned - :returns: list of profile bindings - """ - if context.is_admin: - profile_bindings = _get_profile_bindings( - context.session, - profile_type=c_const.POLICY) - return [self._make_profile_bindings_dict(pb) - for pb in profile_bindings] - - def update_policy_profile(self, context, id, policy_profile): - """ - Update a policy profile. - - Add/remove policy profile to tenant-id binding for the corresponding - option and if user is admin. - :param context: neutron api request context - :param id: UUID representing policy profile to update - :param policy_profile: policy profile dictionary - :returns: updated policy profile dictionary - """ - p = policy_profile["policy_profile"] - if context.is_admin and "add_tenant" in p: - self.add_policy_profile_tenant(context.session, - id, - p["add_tenant"]) - return self._make_policy_profile_dict(get_policy_profile( - context.session, id)) - if context.is_admin and "remove_tenant" in p: - delete_profile_binding(context.session, p["remove_tenant"], id) - return self._make_policy_profile_dict(get_policy_profile( - context.session, id)) - return self._make_policy_profile_dict( - update_policy_profile(context.session, id, p)) - - def add_policy_profile_tenant(self, - db_session, - policy_profile_id, - tenant_id): - """ - Add a tenant to a policy profile binding. - - :param db_session: database session - :param policy_profile_id: UUID representing policy profile - :param tenant_id: UUID representing the tenant - :returns: profile binding object - """ - return create_profile_binding(db_session, - tenant_id, - policy_profile_id, - c_const.POLICY) - - def remove_policy_profile_tenant(self, policy_profile_id, tenant_id): - """ - Remove a tenant to a policy profile binding. - - :param policy_profile_id: UUID representing policy profile - :param tenant_id: UUID representing the tenant - """ - delete_profile_binding(None, tenant_id, policy_profile_id) - - def _delete_policy_profile(self, policy_profile_id): - """Delete policy profile and associated binding.""" - db_session = db.get_session() - with db_session.begin(subtransactions=True): - (db_session.query(n1kv_models_v2.PolicyProfile). - filter_by(id=policy_profile_id).delete()) - - def _get_policy_profile_by_name(self, name): - """ - Retrieve policy profile based on name. - - :param name: string representing the name for the policy profile - :returns: policy profile object - """ - db_session = db.get_session() - with db_session.begin(subtransactions=True): - return (db_session.query(n1kv_models_v2.PolicyProfile). - filter_by(name=name).one()) - - def _remove_all_fake_policy_profiles(self): - """ - Remove all policy profiles associated with fake tenant id. - - This will find all Profile ID where tenant is not set yet - set A - and profiles where tenant was already set - set B - and remove what is in both and no tenant id set - """ - db_session = db.get_session() - with db_session.begin(subtransactions=True): - a_set_q = (db_session.query(n1kv_models_v2.ProfileBinding). - filter_by(tenant_id=c_const.TENANT_ID_NOT_SET, - profile_type=c_const.POLICY)) - a_set = set(i.profile_id for i in a_set_q) - b_set_q = (db_session.query(n1kv_models_v2.ProfileBinding). - filter(sql.and_(n1kv_models_v2.ProfileBinding. - tenant_id != c_const.TENANT_ID_NOT_SET, - n1kv_models_v2.ProfileBinding. - profile_type == c_const.POLICY))) - b_set = set(i.profile_id for i in b_set_q) - (db_session.query(n1kv_models_v2.ProfileBinding). - filter(sql.and_(n1kv_models_v2.ProfileBinding.profile_id. - in_(a_set & b_set), - n1kv_models_v2.ProfileBinding.tenant_id == - c_const.TENANT_ID_NOT_SET)). - delete(synchronize_session="fetch")) - - def _add_policy_profile(self, - policy_profile_name, - policy_profile_id, - tenant_id=None): - """ - Add Policy profile and tenant binding. - - :param policy_profile_name: string representing the name for the - policy profile - :param policy_profile_id: UUID representing the policy profile - :param tenant_id: UUID representing the tenant - """ - policy_profile = {"id": policy_profile_id, "name": policy_profile_name} - tenant_id = tenant_id or c_const.TENANT_ID_NOT_SET - if not self._policy_profile_exists(policy_profile_id): - create_policy_profile(policy_profile) - create_profile_binding(None, - tenant_id, - policy_profile["id"], - c_const.POLICY) diff --git a/neutron/plugins/cisco/db/n1kv_models_v2.py b/neutron/plugins/cisco/db/n1kv_models_v2.py deleted file mode 100644 index 6c81aabba..000000000 --- a/neutron/plugins/cisco/db/n1kv_models_v2.py +++ /dev/null @@ -1,185 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cisco Systems, Inc. -# -# 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: Abhishek Raut, Cisco Systems Inc. -# @author: Rudrajit Tapadar, Cisco Systems Inc. - -import sqlalchemy as sa - -from neutron.db import model_base -from neutron.db import models_v2 -from neutron.openstack.common import log as logging -from neutron.plugins.cisco.common import cisco_constants - - -LOG = logging.getLogger(__name__) - - -class N1kvVlanAllocation(model_base.BASEV2): - - """Represents allocation state of vlan_id on physical network.""" - __tablename__ = 'cisco_n1kv_vlan_allocations' - - physical_network = sa.Column(sa.String(64), - nullable=False, - primary_key=True) - vlan_id = sa.Column(sa.Integer, nullable=False, primary_key=True, - autoincrement=False) - allocated = sa.Column(sa.Boolean, nullable=False, default=False) - network_profile_id = sa.Column(sa.String(36), - sa.ForeignKey('cisco_network_profiles.id', - ondelete="CASCADE"), - nullable=False) - - -class N1kvVxlanAllocation(model_base.BASEV2): - - """Represents allocation state of vxlan_id.""" - __tablename__ = 'cisco_n1kv_vxlan_allocations' - - vxlan_id = sa.Column(sa.Integer, nullable=False, primary_key=True, - autoincrement=False) - allocated = sa.Column(sa.Boolean, nullable=False, default=False) - network_profile_id = sa.Column(sa.String(36), - sa.ForeignKey('cisco_network_profiles.id', - ondelete="CASCADE"), - nullable=False) - - -class N1kvPortBinding(model_base.BASEV2): - - """Represents binding of ports to policy profile.""" - __tablename__ = 'cisco_n1kv_port_bindings' - - port_id = sa.Column(sa.String(36), - sa.ForeignKey('ports.id', ondelete="CASCADE"), - primary_key=True) - profile_id = sa.Column(sa.String(36), - sa.ForeignKey('cisco_policy_profiles.id')) - - -class N1kvNetworkBinding(model_base.BASEV2): - - """Represents binding of virtual network to physical realization.""" - __tablename__ = 'cisco_n1kv_network_bindings' - - network_id = sa.Column(sa.String(36), - sa.ForeignKey('networks.id', ondelete="CASCADE"), - primary_key=True) - network_type = sa.Column(sa.String(32), nullable=False) - physical_network = sa.Column(sa.String(64)) - segmentation_id = sa.Column(sa.Integer) - multicast_ip = sa.Column(sa.String(32)) - profile_id = sa.Column(sa.String(36), - sa.ForeignKey('cisco_network_profiles.id')) - - -class N1kVmNetwork(model_base.BASEV2): - - """Represents VM Network information.""" - __tablename__ = 'cisco_n1kv_vmnetworks' - - name = sa.Column(sa.String(80), primary_key=True) - profile_id = sa.Column(sa.String(36), - sa.ForeignKey('cisco_policy_profiles.id')) - network_id = sa.Column(sa.String(36)) - port_count = sa.Column(sa.Integer) - - -class NetworkProfile(model_base.BASEV2, models_v2.HasId): - - """ - Nexus1000V Network Profiles - - segment_type - VLAN, OVERLAY, TRUNK, MULTI_SEGMENT - sub_type - TRUNK_VLAN, TRUNK_VXLAN, native_vxlan, enhanced_vxlan - segment_range - '-' - multicast_ip_index - - multicast_ip_range - '-' - physical_network - Name for the physical network - """ - __tablename__ = 'cisco_network_profiles' - - name = sa.Column(sa.String(255)) - segment_type = sa.Column(sa.Enum(cisco_constants.NETWORK_TYPE_VLAN, - cisco_constants.NETWORK_TYPE_OVERLAY, - cisco_constants.NETWORK_TYPE_TRUNK, - cisco_constants. - NETWORK_TYPE_MULTI_SEGMENT, - name='segment_type'), - nullable=False) - sub_type = sa.Column(sa.String(255)) - segment_range = sa.Column(sa.String(255)) - multicast_ip_index = sa.Column(sa.Integer, default=0) - multicast_ip_range = sa.Column(sa.String(255)) - physical_network = sa.Column(sa.String(255)) - - -class PolicyProfile(model_base.BASEV2): - - """ - Nexus1000V Network Profiles - - Both 'id' and 'name' are coming from Nexus1000V switch - """ - __tablename__ = 'cisco_policy_profiles' - - id = sa.Column(sa.String(36), primary_key=True) - name = sa.Column(sa.String(255)) - - -class ProfileBinding(model_base.BASEV2): - - """ - Represents a binding of Network Profile - or Policy Profile to tenant_id - """ - __tablename__ = 'cisco_n1kv_profile_bindings' - - profile_type = sa.Column(sa.Enum(cisco_constants.NETWORK, - cisco_constants.POLICY, - name='profile_type')) - tenant_id = sa.Column(sa.String(36), - primary_key=True, - default=cisco_constants.TENANT_ID_NOT_SET) - profile_id = sa.Column(sa.String(36), primary_key=True) - - -class N1kvTrunkSegmentBinding(model_base.BASEV2): - - """Represents binding of segments in trunk networks.""" - __tablename__ = 'cisco_n1kv_trunk_segments' - - trunk_segment_id = sa.Column(sa.String(36), - sa.ForeignKey('networks.id', - ondelete="CASCADE"), - primary_key=True) - segment_id = sa.Column(sa.String(36), nullable=False, primary_key=True) - dot1qtag = sa.Column(sa.String(36), nullable=False, primary_key=True) - - -class N1kvMultiSegmentNetworkBinding(model_base.BASEV2): - - """Represents binding of segments in multi-segment networks.""" - __tablename__ = 'cisco_n1kv_multi_segments' - - multi_segment_id = sa.Column(sa.String(36), - sa.ForeignKey('networks.id', - ondelete="CASCADE"), - primary_key=True) - segment1_id = sa.Column(sa.String(36), nullable=False, primary_key=True) - segment2_id = sa.Column(sa.String(36), nullable=False, primary_key=True) - encap_profile_name = sa.Column(sa.String(36)) diff --git a/neutron/plugins/cisco/db/network_db_v2.py b/neutron/plugins/cisco/db/network_db_v2.py deleted file mode 100644 index 94c5a37de..000000000 --- a/neutron/plugins/cisco/db/network_db_v2.py +++ /dev/null @@ -1,290 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012, Cisco Systems, Inc. -# -# 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: Rohit Agarwalla, Cisco Systems, Inc. - -from sqlalchemy.orm import exc - -from neutron.db import api as db -from neutron.openstack.common import log as logging -from neutron.openstack.common import uuidutils -from neutron.plugins.cisco.common import cisco_constants as const -from neutron.plugins.cisco.common import cisco_exceptions as c_exc -from neutron.plugins.cisco.db import network_models_v2 -# Do NOT remove this import. It is required for all the models to be seen -# by db.initialize() when called from VirtualPhysicalSwitchModelV2.__init__. -from neutron.plugins.cisco.db import nexus_models_v2 # noqa -from neutron.plugins.openvswitch import ovs_models_v2 - - -LOG = logging.getLogger(__name__) - - -def get_all_qoss(tenant_id): - """Lists all the qos to tenant associations.""" - LOG.debug(_("get_all_qoss() called")) - session = db.get_session() - return (session.query(network_models_v2.QoS). - filter_by(tenant_id=tenant_id).all()) - - -def get_qos(tenant_id, qos_id): - """Lists the qos given a tenant_id and qos_id.""" - LOG.debug(_("get_qos() called")) - session = db.get_session() - try: - return (session.query(network_models_v2.QoS). - filter_by(tenant_id=tenant_id). - filter_by(qos_id=qos_id).one()) - except exc.NoResultFound: - raise c_exc.QosNotFound(qos_id=qos_id, - tenant_id=tenant_id) - - -def add_qos(tenant_id, qos_name, qos_desc): - """Adds a qos to tenant association.""" - LOG.debug(_("add_qos() called")) - session = db.get_session() - try: - qos = (session.query(network_models_v2.QoS). - filter_by(tenant_id=tenant_id). - filter_by(qos_name=qos_name).one()) - raise c_exc.QosNameAlreadyExists(qos_name=qos_name, - tenant_id=tenant_id) - except exc.NoResultFound: - qos = network_models_v2.QoS(qos_id=uuidutils.generate_uuid(), - tenant_id=tenant_id, - qos_name=qos_name, - qos_desc=qos_desc) - session.add(qos) - session.flush() - return qos - - -def remove_qos(tenant_id, qos_id): - """Removes a qos to tenant association.""" - session = db.get_session() - try: - qos = (session.query(network_models_v2.QoS). - filter_by(tenant_id=tenant_id). - filter_by(qos_id=qos_id).one()) - session.delete(qos) - session.flush() - return qos - except exc.NoResultFound: - pass - - -def update_qos(tenant_id, qos_id, new_qos_name=None): - """Updates a qos to tenant association.""" - session = db.get_session() - try: - qos = (session.query(network_models_v2.QoS). - filter_by(tenant_id=tenant_id). - filter_by(qos_id=qos_id).one()) - if new_qos_name: - qos["qos_name"] = new_qos_name - session.merge(qos) - session.flush() - return qos - except exc.NoResultFound: - raise c_exc.QosNotFound(qos_id=qos_id, - tenant_id=tenant_id) - - -def get_all_credentials(): - """Lists all the creds for a tenant.""" - session = db.get_session() - return (session.query(network_models_v2.Credential).all()) - - -def get_credential(credential_id): - """Lists the creds for given a cred_id.""" - session = db.get_session() - try: - return (session.query(network_models_v2.Credential). - filter_by(credential_id=credential_id).one()) - except exc.NoResultFound: - raise c_exc.CredentialNotFound(credential_id=credential_id) - - -def get_credential_name(credential_name): - """Lists the creds for given a cred_name.""" - session = db.get_session() - try: - return (session.query(network_models_v2.Credential). - filter_by(credential_name=credential_name).one()) - except exc.NoResultFound: - raise c_exc.CredentialNameNotFound(credential_name=credential_name) - - -def add_credential(credential_name, user_name, password, type): - """Create a credential.""" - session = db.get_session() - try: - cred = (session.query(network_models_v2.Credential). - filter_by(credential_name=credential_name).one()) - raise c_exc.CredentialAlreadyExists(credential_name=credential_name) - except exc.NoResultFound: - cred = network_models_v2.Credential( - credential_id=uuidutils.generate_uuid(), - credential_name=credential_name, - user_name=user_name, - password=password, - type=type) - session.add(cred) - session.flush() - return cred - - -def remove_credential(credential_id): - """Removes a credential.""" - session = db.get_session() - try: - cred = (session.query(network_models_v2.Credential). - filter_by(credential_id=credential_id).one()) - session.delete(cred) - session.flush() - return cred - except exc.NoResultFound: - pass - - -def update_credential(credential_id, - new_user_name=None, new_password=None): - """Updates a credential for a tenant.""" - session = db.get_session() - try: - cred = (session.query(network_models_v2.Credential). - filter_by(credential_id=credential_id).one()) - if new_user_name: - cred["user_name"] = new_user_name - if new_password: - cred["password"] = new_password - session.merge(cred) - session.flush() - return cred - except exc.NoResultFound: - raise c_exc.CredentialNotFound(credential_id=credential_id) - - -def get_all_n1kv_credentials(): - session = db.get_session() - return (session.query(network_models_v2.Credential). - filter_by(type='n1kv')) - - -def add_provider_network(network_id, network_type, segmentation_id): - """Add a network to the provider network table.""" - session = db.get_session() - if session.query(network_models_v2.ProviderNetwork).filter_by( - network_id=network_id).first(): - raise c_exc.ProviderNetworkExists(network_id) - pnet = network_models_v2.ProviderNetwork(network_id=network_id, - network_type=network_type, - segmentation_id=segmentation_id) - session.add(pnet) - session.flush() - - -def remove_provider_network(network_id): - """Remove network_id from the provider network table. - - :param network_id: Any network id. If it is not in the table, do nothing. - :return: network_id if it was in the table and successfully removed. - """ - session = db.get_session() - pnet = (session.query(network_models_v2.ProviderNetwork). - filter_by(network_id=network_id).first()) - if pnet: - session.delete(pnet) - session.flush() - return network_id - - -def is_provider_network(network_id): - """Return True if network_id is in the provider network table.""" - session = db.get_session() - if session.query(network_models_v2.ProviderNetwork).filter_by( - network_id=network_id).first(): - return True - - -def is_provider_vlan(vlan_id): - """Check for a for a vlan provider network with the specified vland_id. - - Returns True if the provider network table contains a vlan network - with the specified vlan_id. - """ - session = db.get_session() - if (session.query(network_models_v2.ProviderNetwork). - filter_by(network_type=const.NETWORK_TYPE_VLAN, - segmentation_id=vlan_id).first()): - return True - - -def get_ovs_vlans(): - session = db.get_session() - bindings = (session.query(ovs_models_v2.VlanAllocation.vlan_id). - filter_by(allocated=True)) - return [binding.vlan_id for binding in bindings] - - -class Credential_db_mixin(object): - - """Mixin class for Cisco Credentials as a resource.""" - - def _make_credential_dict(self, credential, fields=None): - res = {'credential_id': credential['credential_id'], - 'credential_name': credential['credential_name'], - 'user_name': credential['user_name'], - 'password': credential['password'], - 'type': credential['type']} - return self._fields(res, fields) - - def create_credential(self, context, credential): - """Create a credential.""" - c = credential['credential'] - cred = add_credential(c['credential_name'], - c['user_name'], - c['password'], - c['type']) - return self._make_credential_dict(cred) - - def get_credentials(self, context, filters=None, fields=None): - """Retrieve a list of credentials.""" - return self._get_collection(context, - network_models_v2.Credential, - self._make_credential_dict, - filters=filters, - fields=fields) - - def get_credential(self, context, id, fields=None): - """Retireve the requested credential based on its id.""" - credential = get_credential(id) - return self._make_credential_dict(credential, fields) - - def update_credential(self, context, id, credential): - """Update a credential based on its id.""" - c = credential['credential'] - cred = update_credential(id, - c['user_name'], - c['password']) - return self._make_credential_dict(cred) - - def delete_credential(self, context, id): - """Delete a credential based on its id.""" - return remove_credential(id) diff --git a/neutron/plugins/cisco/db/network_models_v2.py b/neutron/plugins/cisco/db/network_models_v2.py deleted file mode 100644 index 49768371d..000000000 --- a/neutron/plugins/cisco/db/network_models_v2.py +++ /dev/null @@ -1,56 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012, Cisco Systems, Inc. -# -# 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: Rohit Agarwalla, Cisco Systems, Inc. - -import sqlalchemy as sa - -from neutron.db import model_base - - -class QoS(model_base.BASEV2): - """Represents QoS policies for a tenant.""" - - __tablename__ = 'cisco_qos_policies' - - qos_id = sa.Column(sa.String(255)) - tenant_id = sa.Column(sa.String(255), primary_key=True) - qos_name = sa.Column(sa.String(255), primary_key=True) - qos_desc = sa.Column(sa.String(255)) - - -class Credential(model_base.BASEV2): - """Represents credentials for a tenant to control Cisco switches.""" - - __tablename__ = 'cisco_credentials' - - credential_id = sa.Column(sa.String(255)) - credential_name = sa.Column(sa.String(255), primary_key=True) - user_name = sa.Column(sa.String(255)) - password = sa.Column(sa.String(255)) - type = sa.Column(sa.String(255)) - - -class ProviderNetwork(model_base.BASEV2): - """Represents networks that were created as provider networks.""" - - __tablename__ = 'cisco_provider_networks' - - network_id = sa.Column(sa.String(36), - sa.ForeignKey('networks.id', ondelete="CASCADE"), - primary_key=True) - network_type = sa.Column(sa.String(255), nullable=False) - segmentation_id = sa.Column(sa.Integer, nullable=False) diff --git a/neutron/plugins/cisco/db/nexus_db_v2.py b/neutron/plugins/cisco/db/nexus_db_v2.py deleted file mode 100644 index a11a8a041..000000000 --- a/neutron/plugins/cisco/db/nexus_db_v2.py +++ /dev/null @@ -1,154 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012, Cisco Systems, Inc. -# -# 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: Rohit Agarwalla, Cisco Systems, Inc. -# @author: Arvind Somya, Cisco Systems, Inc. (asomya@cisco.com) -# - -import sqlalchemy.orm.exc as sa_exc - -import neutron.db.api as db -from neutron.openstack.common import log as logging -from neutron.plugins.cisco.common import cisco_exceptions as c_exc -from neutron.plugins.cisco.db import nexus_models_v2 - - -LOG = logging.getLogger(__name__) - - -def get_nexusport_binding(port_id, vlan_id, switch_ip, instance_id): - """Lists a nexusport binding.""" - LOG.debug(_("get_nexusport_binding() called")) - return _lookup_all_nexus_bindings(port_id=port_id, - vlan_id=vlan_id, - switch_ip=switch_ip, - instance_id=instance_id) - - -def get_nexusvlan_binding(vlan_id, switch_ip): - """Lists a vlan and switch binding.""" - LOG.debug(_("get_nexusvlan_binding() called")) - return _lookup_all_nexus_bindings(vlan_id=vlan_id, switch_ip=switch_ip) - - -def add_nexusport_binding(port_id, vlan_id, switch_ip, instance_id): - """Adds a nexusport binding.""" - LOG.debug(_("add_nexusport_binding() called")) - session = db.get_session() - binding = nexus_models_v2.NexusPortBinding(port_id=port_id, - vlan_id=vlan_id, - switch_ip=switch_ip, - instance_id=instance_id) - session.add(binding) - session.flush() - return binding - - -def remove_nexusport_binding(port_id, vlan_id, switch_ip, instance_id): - """Removes a nexusport binding.""" - LOG.debug(_("remove_nexusport_binding() called")) - session = db.get_session() - binding = _lookup_all_nexus_bindings(session=session, - vlan_id=vlan_id, - switch_ip=switch_ip, - port_id=port_id, - instance_id=instance_id) - for bind in binding: - session.delete(bind) - session.flush() - return binding - - -def update_nexusport_binding(port_id, new_vlan_id): - """Updates nexusport binding.""" - if not new_vlan_id: - LOG.warning(_("update_nexusport_binding called with no vlan")) - return - LOG.debug(_("update_nexusport_binding called")) - session = db.get_session() - binding = _lookup_one_nexus_binding(session=session, port_id=port_id) - binding.vlan_id = new_vlan_id - session.merge(binding) - session.flush() - return binding - - -def get_nexusvm_bindings(vlan_id, instance_id): - """Lists nexusvm bindings.""" - LOG.debug(_("get_nexusvm_binding() called")) - - return _lookup_all_nexus_bindings(vlan_id=vlan_id, - instance_id=instance_id) - - -def get_port_vlan_switch_binding(port_id, vlan_id, switch_ip): - """Lists nexusvm bindings.""" - LOG.debug(_("get_port_vlan_switch_binding() called")) - return _lookup_all_nexus_bindings(port_id=port_id, - switch_ip=switch_ip, - vlan_id=vlan_id) - - -def get_port_switch_bindings(port_id, switch_ip): - """List all vm/vlan bindings on a Nexus switch port.""" - LOG.debug(_("get_port_switch_bindings() called, " - "port:'%(port_id)s', switch:'%(switch_ip)s'"), - {'port_id': port_id, 'switch_ip': switch_ip}) - try: - return _lookup_all_nexus_bindings(port_id=port_id, - switch_ip=switch_ip) - except c_exc.NexusPortBindingNotFound: - pass - - -def get_nexussvi_bindings(): - """Lists nexus svi bindings.""" - LOG.debug(_("get_nexussvi_bindings() called")) - return _lookup_all_nexus_bindings(port_id='router') - - -def _lookup_nexus_bindings(query_type, session=None, **bfilter): - """Look up 'query_type' Nexus bindings matching the filter. - - :param query_type: 'all', 'one' or 'first' - :param session: db session - :param bfilter: filter for bindings query - :return: bindings if query gave a result, else - raise NexusPortBindingNotFound. - """ - if session is None: - session = db.get_session() - query_method = getattr(session.query( - nexus_models_v2.NexusPortBinding).filter_by(**bfilter), query_type) - try: - bindings = query_method() - if bindings: - return bindings - except sa_exc.NoResultFound: - pass - raise c_exc.NexusPortBindingNotFound(**bfilter) - - -def _lookup_all_nexus_bindings(session=None, **bfilter): - return _lookup_nexus_bindings('all', session, **bfilter) - - -def _lookup_one_nexus_binding(session=None, **bfilter): - return _lookup_nexus_bindings('one', session, **bfilter) - - -def _lookup_first_nexus_binding(session=None, **bfilter): - return _lookup_nexus_bindings('first', session, **bfilter) diff --git a/neutron/plugins/cisco/db/nexus_models_v2.py b/neutron/plugins/cisco/db/nexus_models_v2.py deleted file mode 100644 index e639e47c6..000000000 --- a/neutron/plugins/cisco/db/nexus_models_v2.py +++ /dev/null @@ -1,46 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012, Cisco Systems, Inc. -# -# 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: Rohit Agarwalla, Cisco Systems, Inc. - -import sqlalchemy as sa - -from neutron.db import model_base - - -class NexusPortBinding(model_base.BASEV2): - """Represents a binding of VM's to nexus ports.""" - - __tablename__ = "cisco_nexusport_bindings" - - id = sa.Column(sa.Integer, primary_key=True, autoincrement=True) - port_id = sa.Column(sa.String(255)) - vlan_id = sa.Column(sa.Integer, nullable=False) - switch_ip = sa.Column(sa.String(255), nullable=False) - instance_id = sa.Column(sa.String(255), nullable=False) - - def __repr__(self): - """Just the binding, without the id key.""" - return ("" % - (self.port_id, self.vlan_id, self.switch_ip, self.instance_id)) - - def __eq__(self, other): - """Compare only the binding, without the id key.""" - return ( - self.port_id == other.port_id and - self.vlan_id == other.vlan_id and - self.switch_ip == other.switch_ip and - self.instance_id == other.instance_id - ) diff --git a/neutron/plugins/cisco/extensions/__init__.py b/neutron/plugins/cisco/extensions/__init__.py deleted file mode 100644 index 63082aba2..000000000 --- a/neutron/plugins/cisco/extensions/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 OpenStack Foundation. -# 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. diff --git a/neutron/plugins/cisco/extensions/_credential_view.py b/neutron/plugins/cisco/extensions/_credential_view.py deleted file mode 100644 index 9dcbbc81e..000000000 --- a/neutron/plugins/cisco/extensions/_credential_view.py +++ /dev/null @@ -1,52 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 Cisco Systems, Inc. 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: Ying Liu, Cisco Systems, Inc. -# - - -def get_view_builder(req): - base_url = req.application_url - return ViewBuilder(base_url) - - -class ViewBuilder(object): - """ViewBuilder for Credential, derived from neutron.views.networks.""" - - def __init__(self, base_url): - """Initialize builder. - - :param base_url: url of the root wsgi application - """ - self.base_url = base_url - - def build(self, credential_data, is_detail=False): - """Generic method used to generate a credential entity.""" - if is_detail: - credential = self._build_detail(credential_data) - else: - credential = self._build_simple(credential_data) - return credential - - def _build_simple(self, credential_data): - """Return a simple description of credential.""" - return dict(credential=dict(id=credential_data['credential_id'])) - - def _build_detail(self, credential_data): - """Return a detailed description of credential.""" - return dict(credential=dict(id=credential_data['credential_id'], - name=credential_data['user_name'], - password=credential_data['password'])) diff --git a/neutron/plugins/cisco/extensions/_qos_view.py b/neutron/plugins/cisco/extensions/_qos_view.py deleted file mode 100644 index 81ef5fef6..000000000 --- a/neutron/plugins/cisco/extensions/_qos_view.py +++ /dev/null @@ -1,52 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 Cisco Systems, Inc. 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: Ying Liu, Cisco Systems, Inc. -# - - -def get_view_builder(req): - base_url = req.application_url - return ViewBuilder(base_url) - - -class ViewBuilder(object): - """ViewBuilder for QoS, derived from neutron.views.networks.""" - - def __init__(self, base_url): - """Initialize builder. - - :param base_url: url of the root wsgi application - """ - self.base_url = base_url - - def build(self, qos_data, is_detail=False): - """Generic method used to generate a QoS entity.""" - if is_detail: - qos = self._build_detail(qos_data) - else: - qos = self._build_simple(qos_data) - return qos - - def _build_simple(self, qos_data): - """Return a simple description of qos.""" - return dict(qos=dict(id=qos_data['qos_id'])) - - def _build_detail(self, qos_data): - """Return a detailed description of qos.""" - return dict(qos=dict(id=qos_data['qos_id'], - name=qos_data['qos_name'], - description=qos_data['qos_desc'])) diff --git a/neutron/plugins/cisco/extensions/credential.py b/neutron/plugins/cisco/extensions/credential.py deleted file mode 100644 index 8838136c1..000000000 --- a/neutron/plugins/cisco/extensions/credential.py +++ /dev/null @@ -1,84 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cisco Systems, Inc. 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: Ying Liu, Cisco Systems, Inc. -# @author: Abhishek Raut, Cisco Systems, Inc - -from neutron.api import extensions -from neutron.api.v2 import attributes -from neutron.api.v2 import base -from neutron import manager - - -# Attribute Map -RESOURCE_ATTRIBUTE_MAP = { - 'credentials': { - 'credential_id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:regex': attributes.UUID_PATTERN}, - 'is_visible': True}, - 'credential_name': {'allow_post': True, 'allow_put': True, - 'is_visible': True, 'default': ''}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'is_visible': False, 'default': ''}, - 'type': {'allow_post': True, 'allow_put': True, - 'is_visible': True, 'default': ''}, - 'user_name': {'allow_post': True, 'allow_put': True, - 'is_visible': True, 'default': ''}, - 'password': {'allow_post': True, 'allow_put': True, - 'is_visible': True, 'default': ''}, - }, -} - - -class Credential(extensions.ExtensionDescriptor): - - @classmethod - def get_name(cls): - """Returns Extended Resource Name.""" - return "Cisco Credential" - - @classmethod - def get_alias(cls): - """Returns Extended Resource Alias.""" - return "credential" - - @classmethod - def get_description(cls): - """Returns Extended Resource Description.""" - return "Credential include username and password" - - @classmethod - def get_namespace(cls): - """Returns Extended Resource Namespace.""" - return "http://docs.ciscocloud.com/api/ext/credential/v2.0" - - @classmethod - def get_updated(cls): - """Returns Extended Resource Update Time.""" - return "2011-07-25T13:25:27-06:00" - - @classmethod - def get_resources(cls): - """Returns Extended Resources.""" - resource_name = "credential" - collection_name = resource_name + "s" - plugin = manager.NeutronManager.get_plugin() - params = RESOURCE_ATTRIBUTE_MAP.get(collection_name, dict()) - controller = base.create_resource(collection_name, - resource_name, - plugin, params) - return [extensions.ResourceExtension(collection_name, - controller)] diff --git a/neutron/plugins/cisco/extensions/n1kv.py b/neutron/plugins/cisco/extensions/n1kv.py deleted file mode 100644 index 352ad816a..000000000 --- a/neutron/plugins/cisco/extensions/n1kv.py +++ /dev/null @@ -1,106 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cisco Systems, Inc. -# -# 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: Abhishek Raut, Cisco Systems, Inc. -# @author: Rudrajit Tapadar, Cisco Systems, Inc. -# @author: Aruna Kushwaha, Cisco Systems, Inc. -# @author: Sergey Sudakovich, Cisco Systems, Inc. - -from neutron.api import extensions -from neutron.api.v2 import attributes - - -PROFILE_ID = 'n1kv:profile_id' -MULTICAST_IP = 'n1kv:multicast_ip' -SEGMENT_ADD = 'n1kv:segment_add' -SEGMENT_DEL = 'n1kv:segment_del' -MEMBER_SEGMENTS = 'n1kv:member_segments' - -EXTENDED_ATTRIBUTES_2_0 = { - 'networks': { - PROFILE_ID: {'allow_post': True, 'allow_put': False, - 'validate': {'type:regex': attributes.UUID_PATTERN}, - 'default': attributes.ATTR_NOT_SPECIFIED, - 'is_visible': True}, - MULTICAST_IP: {'allow_post': True, 'allow_put': True, - 'default': attributes.ATTR_NOT_SPECIFIED, - 'is_visible': True}, - SEGMENT_ADD: {'allow_post': True, 'allow_put': True, - 'default': attributes.ATTR_NOT_SPECIFIED, - 'is_visible': True}, - SEGMENT_DEL: {'allow_post': True, 'allow_put': True, - 'default': attributes.ATTR_NOT_SPECIFIED, - 'is_visible': True}, - MEMBER_SEGMENTS: {'allow_post': True, 'allow_put': True, - 'default': attributes.ATTR_NOT_SPECIFIED, - 'is_visible': True}, - }, - 'ports': { - PROFILE_ID: {'allow_post': True, 'allow_put': False, - 'validate': {'type:regex': attributes.UUID_PATTERN}, - 'default': attributes.ATTR_NOT_SPECIFIED, - 'is_visible': True} - } -} - - -class N1kv(extensions.ExtensionDescriptor): - - """Extension class supporting N1kv profiles. - - This class is used by neutron's extension framework to make - metadata about the n1kv profile extension available to - clients. No new resources are defined by this extension. Instead, - the existing network resource's request and response messages are - extended with attributes in the n1kv profile namespace. - - To create a network based on n1kv profile using the CLI with admin rights: - - (shell) net-create --tenant_id \ - --n1kv:profile_id - (shell) port-create --tenant_id \ - --n1kv:profile_id - - - With admin rights, network dictionaries returned from CLI commands - will also include n1kv profile attributes. - """ - - @classmethod - def get_name(cls): - return "n1kv" - - @classmethod - def get_alias(cls): - return "n1kv" - - @classmethod - def get_description(cls): - return "Expose network profile" - - @classmethod - def get_namespace(cls): - return "http://docs.openstack.org/ext/n1kv/api/v2.0" - - @classmethod - def get_updated(cls): - return "2012-11-15T10:00:00-00:00" - - def get_extended_resources(self, version): - if version == "2.0": - return EXTENDED_ATTRIBUTES_2_0 - else: - return {} diff --git a/neutron/plugins/cisco/extensions/network_profile.py b/neutron/plugins/cisco/extensions/network_profile.py deleted file mode 100644 index bb05bd944..000000000 --- a/neutron/plugins/cisco/extensions/network_profile.py +++ /dev/null @@ -1,103 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cisco Systems, Inc. -# -# 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: Abhishek Raut, Cisco Systems, Inc. -# @author: Sergey Sudakovich, Cisco Systems, Inc. -# @author: Rudrajit Tapadar, Cisco Systems, Inc. - -from neutron.api import extensions -from neutron.api.v2 import attributes -from neutron.api.v2 import base -from neutron import manager - - -# Attribute Map -RESOURCE_ATTRIBUTE_MAP = { - 'network_profiles': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:regex': attributes.UUID_PATTERN}, - 'is_visible': True}, - 'name': {'allow_post': True, 'allow_put': True, - 'is_visible': True, 'default': ''}, - 'segment_type': {'allow_post': True, 'allow_put': False, - 'is_visible': True, 'default': ''}, - 'sub_type': {'allow_post': True, 'allow_put': False, - 'is_visible': True, - 'default': attributes.ATTR_NOT_SPECIFIED}, - 'segment_range': {'allow_post': True, 'allow_put': True, - 'is_visible': True, 'default': ''}, - 'multicast_ip_range': {'allow_post': True, 'allow_put': True, - 'is_visible': True, - 'default': attributes.ATTR_NOT_SPECIFIED}, - 'multicast_ip_index': {'allow_post': False, 'allow_put': False, - 'is_visible': False, 'default': '0'}, - 'physical_network': {'allow_post': True, 'allow_put': False, - 'is_visible': True, 'default': ''}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'is_visible': False, 'default': ''}, - 'add_tenant': {'allow_post': True, 'allow_put': True, - 'is_visible': True, 'default': None}, - 'remove_tenant': {'allow_post': True, 'allow_put': True, - 'is_visible': True, 'default': None}, - }, - 'network_profile_bindings': { - 'profile_id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:regex': attributes.UUID_PATTERN}, - 'is_visible': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'is_visible': True}, - }, -} - - -class Network_profile(extensions.ExtensionDescriptor): - - @classmethod - def get_name(cls): - return "Cisco N1kv Network Profiles" - - @classmethod - def get_alias(cls): - return 'network_profile' - - @classmethod - def get_description(cls): - return ("Profile includes the type of profile for N1kv") - - @classmethod - def get_namespace(cls): - return "http://docs.openstack.org/ext/n1kv/network-profile/api/v2.0" - - @classmethod - def get_updated(cls): - return "2012-07-20T10:00:00-00:00" - - @classmethod - def get_resources(cls): - """Returns Extended Resources.""" - exts = [] - plugin = manager.NeutronManager.get_plugin() - for resource_name in ['network_profile', 'network_profile_binding']: - collection_name = resource_name + "s" - controller = base.create_resource( - collection_name, - resource_name, - plugin, - RESOURCE_ATTRIBUTE_MAP.get(collection_name)) - ex = extensions.ResourceExtension(collection_name, - controller) - exts.append(ex) - return exts diff --git a/neutron/plugins/cisco/extensions/policy_profile.py b/neutron/plugins/cisco/extensions/policy_profile.py deleted file mode 100644 index af3c25083..000000000 --- a/neutron/plugins/cisco/extensions/policy_profile.py +++ /dev/null @@ -1,85 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cisco Systems, Inc. -# -# 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: Abhishek Raut, Cisco Systems, Inc. -# @author: Sergey Sudakovich, Cisco Systems, Inc. - -from neutron.api import extensions -from neutron.api.v2 import attributes -from neutron.api.v2 import base -from neutron import manager - -# Attribute Map -RESOURCE_ATTRIBUTE_MAP = { - 'policy_profiles': { - 'id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:regex': attributes.UUID_PATTERN}, - 'is_visible': True}, - 'name': {'allow_post': False, 'allow_put': False, - 'is_visible': True, 'default': ''}, - 'add_tenant': {'allow_post': True, 'allow_put': True, - 'is_visible': True, 'default': None}, - 'remove_tenant': {'allow_post': True, 'allow_put': True, - 'is_visible': True, 'default': None}, - }, - 'policy_profile_bindings': { - 'profile_id': {'allow_post': False, 'allow_put': False, - 'validate': {'type:regex': attributes.UUID_PATTERN}, - 'is_visible': True}, - 'tenant_id': {'allow_post': True, 'allow_put': False, - 'is_visible': True}, - }, -} - - -class Policy_profile(extensions.ExtensionDescriptor): - - @classmethod - def get_name(cls): - return "Cisco Nexus1000V Policy Profiles" - - @classmethod - def get_alias(cls): - return 'policy_profile' - - @classmethod - def get_description(cls): - return "Profile includes the type of profile for N1kv" - - @classmethod - def get_namespace(cls): - return "http://docs.openstack.org/ext/n1kv/policy-profile/api/v2.0" - - @classmethod - def get_updated(cls): - return "2012-07-20T10:00:00-00:00" - - @classmethod - def get_resources(cls): - """Returns Extended Resources.""" - exts = [] - plugin = manager.NeutronManager.get_plugin() - for resource_name in ['policy_profile', 'policy_profile_binding']: - collection_name = resource_name + "s" - controller = base.create_resource( - collection_name, - resource_name, - plugin, - RESOURCE_ATTRIBUTE_MAP.get(collection_name)) - ex = extensions.ResourceExtension(collection_name, - controller) - exts.append(ex) - return exts diff --git a/neutron/plugins/cisco/extensions/qos.py b/neutron/plugins/cisco/extensions/qos.py deleted file mode 100644 index 255601b5b..000000000 --- a/neutron/plugins/cisco/extensions/qos.py +++ /dev/null @@ -1,156 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2011 Cisco Systems, Inc. -# 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: Ying Liu, Cisco Systems, Inc. -# - -from webob import exc - -from neutron.api import api_common as common -from neutron.api import extensions -from neutron import manager -from neutron.plugins.cisco.common import cisco_exceptions as exception -from neutron.plugins.cisco.common import cisco_faults as faults -from neutron.plugins.cisco.extensions import _qos_view as qos_view -from neutron import wsgi - - -class Qos(extensions.ExtensionDescriptor): - """Qos extension file.""" - - @classmethod - def get_name(cls): - """Returns Ext Resource Name.""" - return "Cisco qos" - - @classmethod - def get_alias(cls): - """Returns Ext Resource Alias.""" - return "Cisco qos" - - @classmethod - def get_description(cls): - """Returns Ext Resource Description.""" - return "qos includes qos_name and qos_desc" - - @classmethod - def get_namespace(cls): - """Returns Ext Resource Namespace.""" - return "http://docs.ciscocloud.com/api/ext/qos/v1.0" - - @classmethod - def get_updated(cls): - """Returns Ext Resource update.""" - return "2011-07-25T13:25:27-06:00" - - @classmethod - def get_resources(cls): - """Returns Ext Resources.""" - parent_resource = dict(member_name="tenant", - collection_name="extensions/csco/tenants") - - controller = QosController(manager.NeutronManager.get_plugin()) - return [extensions.ResourceExtension('qoss', controller, - parent=parent_resource)] - - -class QosController(common.NeutronController, wsgi.Controller): - """qos API controller based on NeutronController.""" - - _qos_ops_param_list = [ - {'param-name': 'qos_name', 'required': True}, - {'param-name': 'qos_desc', 'required': True}, - ] - - _serialization_metadata = { - "application/xml": { - "attributes": { - "qos": ["id", "name"], - }, - }, - } - - def __init__(self, plugin): - self._resource_name = 'qos' - self._plugin = plugin - - def index(self, request, tenant_id): - """Returns a list of qos ids.""" - return self._items(request, tenant_id, is_detail=False) - - def _items(self, request, tenant_id, is_detail): - """Returns a list of qoss.""" - qoss = self._plugin.get_all_qoss(tenant_id) - builder = qos_view.get_view_builder(request) - result = [builder.build(qos, is_detail)['qos'] for qos in qoss] - return dict(qoss=result) - - # pylint: disable-msg=E1101 - def show(self, request, tenant_id, id): - """Returns qos details for the given qos id.""" - try: - qos = self._plugin.get_qos_details(tenant_id, id) - builder = qos_view.get_view_builder(request) - #build response with details - result = builder.build(qos, True) - return dict(qoss=result) - except exception.QosNotFound as exp: - return faults.Fault(faults.QosNotFound(exp)) - - def create(self, request, tenant_id): - """Creates a new qos for a given tenant.""" - #look for qos name in request - try: - body = self._deserialize(request.body, request.get_content_type()) - req_body = self._prepare_request_body(body, - self._qos_ops_param_list) - req_params = req_body[self._resource_name] - except exc.HTTPError as exp: - return faults.Fault(exp) - qos = self._plugin.create_qos(tenant_id, - req_params['qos_name'], - req_params['qos_desc']) - builder = qos_view.get_view_builder(request) - result = builder.build(qos) - return dict(qoss=result) - - def update(self, request, tenant_id, id): - """Updates the name for the qos with the given id.""" - try: - body = self._deserialize(request.body, request.get_content_type()) - req_body = self._prepare_request_body(body, - self._qos_ops_param_list) - req_params = req_body[self._resource_name] - except exc.HTTPError as exp: - return faults.Fault(exp) - try: - qos = self._plugin.rename_qos(tenant_id, id, - req_params['qos_name']) - - builder = qos_view.get_view_builder(request) - result = builder.build(qos, True) - return dict(qoss=result) - except exception.QosNotFound as exp: - return faults.Fault(faults.QosNotFound(exp)) - - def delete(self, request, tenant_id, id): - """Destroys the qos with the given id.""" - try: - self._plugin.delete_qos(tenant_id, id) - return exc.HTTPOk() - except exception.QosNotFound as exp: - return faults.Fault(faults.QosNotFound(exp)) diff --git a/neutron/plugins/cisco/l2device_plugin_base.py b/neutron/plugins/cisco/l2device_plugin_base.py deleted file mode 100644 index ef75e1188..000000000 --- a/neutron/plugins/cisco/l2device_plugin_base.py +++ /dev/null @@ -1,175 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012 Cisco Systems, Inc. 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: Sumit Naiksatam, Cisco Systems, Inc. - -import abc -import inspect -import six - - -@six.add_metaclass(abc.ABCMeta) -class L2DevicePluginBase(object): - """Base class for a device-specific plugin. - - An example of a device-specific plugin is a Nexus switch plugin. - The network model relies on device-category-specific plugins to perform - the configuration on each device. - """ - - @abc.abstractmethod - def create_network(self, tenant_id, net_name, net_id, vlan_name, vlan_id, - **kwargs): - """Create network. - - :returns: - :raises: - """ - pass - - @abc.abstractmethod - def delete_network(self, tenant_id, net_id, **kwargs): - """Delete network. - - :returns: - :raises: - """ - pass - - @abc.abstractmethod - def update_network(self, tenant_id, net_id, name, **kwargs): - """Update network. - - :returns: - :raises: - """ - pass - - @abc.abstractmethod - def create_port(self, tenant_id, net_id, port_state, port_id, **kwargs): - """Create port. - - :returns: - :raises: - """ - pass - - @abc.abstractmethod - def delete_port(self, tenant_id, net_id, port_id, **kwargs): - """Delete port. - - :returns: - :raises: - """ - pass - - @abc.abstractmethod - def update_port(self, tenant_id, net_id, port_id, **kwargs): - """Update port. - - :returns: - :raises: - """ - pass - - @abc.abstractmethod - def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id, - **kwargs): - """Plug interface. - - :returns: - :raises: - """ - pass - - @abc.abstractmethod - def unplug_interface(self, tenant_id, net_id, port_id, **kwargs): - """Unplug interface. - - :returns: - :raises: - """ - pass - - def create_subnet(self, tenant_id, net_id, ip_version, - subnet_cidr, **kwargs): - """Create subnet. - - :returns: - :raises: - """ - pass - - def get_subnets(self, tenant_id, net_id, **kwargs): - """Get subnets. - - :returns: - :raises: - """ - pass - - def get_subnet(self, tenant_id, net_id, subnet_id, **kwargs): - """Get subnet. - - :returns: - :raises: - """ - pass - - def update_subnet(self, tenant_id, net_id, subnet_id, **kwargs): - """Update subnet. - - :returns: - :raises: - """ - pass - - def delete_subnet(self, tenant_id, net_id, subnet_id, **kwargs): - """Delete subnet. - - :returns: - :raises: - """ - pass - - @classmethod - def __subclasshook__(cls, klass): - """Check plugin class. - - The __subclasshook__ method is a class method - that will be called every time a class is tested - using issubclass(klass, Plugin). - In that case, it will check that every method - marked with the abstractmethod decorator is - provided by the plugin class. - """ - if cls is L2DevicePluginBase: - for method in cls.__abstractmethods__: - method_ok = False - for base in klass.__mro__: - if method in base.__dict__: - fn_obj = base.__dict__[method] - if inspect.isfunction(fn_obj): - abstract_fn_obj = cls.__dict__[method] - arg_count = fn_obj.func_code.co_argcount - expected_arg_count = \ - abstract_fn_obj.func_code.co_argcount - method_ok = arg_count == expected_arg_count - if method_ok: - continue - return NotImplemented - return True - return NotImplemented diff --git a/neutron/plugins/cisco/models/__init__.py b/neutron/plugins/cisco/models/__init__.py deleted file mode 100644 index 833357b73..000000000 --- a/neutron/plugins/cisco/models/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 Cisco Systems, Inc. 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: Sumit Naiksatam, Cisco Systems, Inc. diff --git a/neutron/plugins/cisco/models/virt_phy_sw_v2.py b/neutron/plugins/cisco/models/virt_phy_sw_v2.py deleted file mode 100644 index b7452f363..000000000 --- a/neutron/plugins/cisco/models/virt_phy_sw_v2.py +++ /dev/null @@ -1,553 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012 Cisco Systems, Inc. -# 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: Sumit Naiksatam, Cisco Systems, Inc. -# @author: Rohit Agarwalla, Cisco Systems, Inc. -# - -import inspect -import logging -import sys - -from neutron.api.v2 import attributes -from neutron.db import api as db_api -from neutron.extensions import portbindings -from neutron.extensions import providernet as provider -from neutron import neutron_plugin_base_v2 -from neutron.openstack.common import importutils -from neutron.plugins.cisco.common import cisco_constants as const -from neutron.plugins.cisco.common import cisco_credentials_v2 as cred -from neutron.plugins.cisco.common import cisco_exceptions as cexc -from neutron.plugins.cisco.common import config as conf -from neutron.plugins.cisco.db import network_db_v2 as cdb -from neutron.plugins.openvswitch import ovs_db_v2 as odb - - -LOG = logging.getLogger(__name__) - - -class VirtualPhysicalSwitchModelV2(neutron_plugin_base_v2.NeutronPluginBaseV2): - """Virtual Physical Switch Model. - - This implementation works with OVS and Nexus plugin for the - following topology: - One or more servers to a nexus switch. - """ - __native_bulk_support = True - supported_extension_aliases = ["provider", "binding"] - _methods_to_delegate = ['create_network_bulk', - 'get_network', 'get_networks', - 'create_port_bulk', - 'get_port', 'get_ports', - 'create_subnet', 'create_subnet_bulk', - 'delete_subnet', 'update_subnet', - 'get_subnet', 'get_subnets', - 'create_or_update_agent', 'report_state'] - - def __init__(self): - """Initialize the segmentation manager. - - Checks which device plugins are configured, and load the inventories - those device plugins for which the inventory is configured. - """ - conf.CiscoConfigOptions() - - self._plugins = {} - for key in conf.CISCO_PLUGINS.keys(): - plugin_obj = conf.CISCO_PLUGINS[key] - if plugin_obj is not None: - self._plugins[key] = importutils.import_object(plugin_obj) - LOG.debug(_("Loaded device plugin %s"), - conf.CISCO_PLUGINS[key]) - - if ((const.VSWITCH_PLUGIN in self._plugins) and - hasattr(self._plugins[const.VSWITCH_PLUGIN], - "supported_extension_aliases")): - self.supported_extension_aliases.extend( - self._plugins[const.VSWITCH_PLUGIN]. - supported_extension_aliases) - # At this point, all the database models should have been loaded. It's - # possible that configure_db() may have been called by one of the - # plugins loaded in above. Otherwise, this call is to make sure that - # the database is initialized - db_api.configure_db() - - # Initialize credential store after database initialization - cred.Store.initialize() - LOG.debug(_("%(module)s.%(name)s init done"), - {'module': __name__, - 'name': self.__class__.__name__}) - - # Check whether we have a valid Nexus driver loaded - self.is_nexus_plugin = False - nexus_driver = conf.CISCO.nexus_driver - if nexus_driver.endswith('CiscoNEXUSDriver'): - self.is_nexus_plugin = True - - def __getattribute__(self, name): - """Delegate calls to OVS sub-plugin. - - This delegates the calls to the methods implemented only by the OVS - sub-plugin. Note: Currently, bulking is handled by the caller - (PluginV2), and this model class expects to receive only non-bulking - calls. If, however, a bulking call is made, this will method will - delegate the call to the OVS plugin. - """ - super_getattribute = super(VirtualPhysicalSwitchModelV2, - self).__getattribute__ - methods = super_getattribute('_methods_to_delegate') - - if name in methods: - plugin = super_getattribute('_plugins')[const.VSWITCH_PLUGIN] - return getattr(plugin, name) - - try: - return super_getattribute(name) - except AttributeError: - plugin = super_getattribute('_plugins')[const.VSWITCH_PLUGIN] - return getattr(plugin, name) - - def _func_name(self, offset=0): - """Get the name of the calling function.""" - frame_record = inspect.stack()[1 + offset] - func_name = frame_record[3] - return func_name - - def _invoke_plugin_per_device(self, plugin_key, function_name, - args, **kwargs): - """Invoke plugin per device. - - Invokes a device plugin's relevant functions (based on the - plugin implementation) for completing this operation. - """ - if plugin_key not in self._plugins: - LOG.info(_("No %s Plugin loaded"), plugin_key) - LOG.info(_("%(plugin_key)s: %(function_name)s with args %(args)s " - "ignored"), - {'plugin_key': plugin_key, - 'function_name': function_name, - 'args': args}) - else: - func = getattr(self._plugins[plugin_key], function_name) - return func(*args, **kwargs) - - def _get_segmentation_id(self, network_id): - binding_seg_id = odb.get_network_binding(None, network_id) - if not binding_seg_id: - raise cexc.NetworkSegmentIDNotFound(net_id=network_id) - return binding_seg_id.segmentation_id - - def _get_provider_vlan_id(self, network): - if (all(attributes.is_attr_set(network.get(attr)) - for attr in (provider.NETWORK_TYPE, - provider.PHYSICAL_NETWORK, - provider.SEGMENTATION_ID)) - and - network[provider.NETWORK_TYPE] == const.NETWORK_TYPE_VLAN): - return network[provider.SEGMENTATION_ID] - - def create_network(self, context, network): - """Create network. - - Perform this operation in the context of the configured device - plugins. - """ - LOG.debug(_("create_network() called")) - provider_vlan_id = self._get_provider_vlan_id(network[const.NETWORK]) - args = [context, network] - ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN, - self._func_name(), - args) - # The vswitch plugin did all the verification. If it's a provider - # vlan network, save it for the nexus plugin to use later. - if provider_vlan_id: - network_id = ovs_output[const.NET_ID] - cdb.add_provider_network(network_id, - const.NETWORK_TYPE_VLAN, - provider_vlan_id) - LOG.debug(_("Provider network added to DB: %(network_id)s, " - "%(vlan_id)s"), - {'network_id': network_id, 'vlan_id': provider_vlan_id}) - return ovs_output - - def update_network(self, context, id, network): - """Update network. - - Perform this operation in the context of the configured device - plugins. - - Note that the Nexus sub-plugin does not need to be notified - (and the Nexus switch does not need to be [re]configured) - for an update network operation because the Nexus sub-plugin - is agnostic of all network-level attributes except the - segmentation ID. Furthermore, updating of the segmentation ID - is not supported by the OVS plugin since it is considered a - provider attribute, so it is not supported by this method. - """ - LOG.debug(_("update_network() called")) - - # We can only support updating of provider attributes if all the - # configured sub-plugins support it. Currently we have no method - # in place for checking whether a sub-plugin supports it, - # so assume not. - provider._raise_if_updates_provider_attributes(network['network']) - - args = [context, id, network] - return self._invoke_plugin_per_device(const.VSWITCH_PLUGIN, - self._func_name(), - args) - - def delete_network(self, context, id): - """Delete network. - - Perform this operation in the context of the configured device - plugins. - """ - args = [context, id] - ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN, - self._func_name(), - args) - if cdb.remove_provider_network(id): - LOG.debug(_("Provider network removed from DB: %s"), id) - return ovs_output - - def get_network(self, context, id, fields=None): - """Get network. This method is delegated to the vswitch plugin. - - This method is included here to satisfy abstract method requirements. - """ - pass # pragma no cover - - def get_networks(self, context, filters=None, fields=None, - sorts=None, limit=None, marker=None, page_reverse=False): - """Get networks. This method is delegated to the vswitch plugin. - - This method is included here to satisfy abstract method requirements. - """ - pass # pragma no cover - - def _invoke_nexus_for_net_create(self, context, tenant_id, net_id, - instance_id, host_id): - if not self.is_nexus_plugin: - return False - - network = self.get_network(context, net_id) - vlan_id = self._get_segmentation_id(net_id) - vlan_name = conf.CISCO.vlan_name_prefix + str(vlan_id) - network[const.NET_VLAN_ID] = vlan_id - network[const.NET_VLAN_NAME] = vlan_name - attachment = { - const.TENANT_ID: tenant_id, - const.INSTANCE_ID: instance_id, - const.HOST_NAME: host_id, - } - self._invoke_plugin_per_device( - const.NEXUS_PLUGIN, - 'create_network', - [network, attachment]) - - def _check_valid_port_device_owner(self, port): - """Check the port for valid device_owner. - - Don't call the nexus plugin for router and dhcp - port owners. - """ - return port['device_owner'].startswith('compute') - - def _get_port_host_id_from_bindings(self, port): - """Get host_id from portbindings.""" - host_id = None - - if (portbindings.HOST_ID in port and - attributes.is_attr_set(port[portbindings.HOST_ID])): - host_id = port[portbindings.HOST_ID] - - return host_id - - def create_port(self, context, port): - """Create port. - - Perform this operation in the context of the configured device - plugins. - """ - LOG.debug(_("create_port() called")) - args = [context, port] - ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN, - self._func_name(), - args) - instance_id = port['port']['device_id'] - - # Only call nexus plugin if there's a valid instance_id, host_id - # and device_owner - try: - host_id = self._get_port_host_id_from_bindings(port['port']) - if (instance_id and host_id and - self._check_valid_port_device_owner(port['port'])): - net_id = port['port']['network_id'] - tenant_id = port['port']['tenant_id'] - self._invoke_nexus_for_net_create( - context, tenant_id, net_id, instance_id, host_id) - except Exception: - # Create network on the Nexus plugin has failed, so we need - # to rollback the port creation on the VSwitch plugin. - exc_info = sys.exc_info() - try: - id = ovs_output['id'] - args = [context, id] - ovs_output = self._invoke_plugin_per_device( - const.VSWITCH_PLUGIN, - 'delete_port', - args) - finally: - # Re-raise the original exception - raise exc_info[0], exc_info[1], exc_info[2] - return ovs_output - - def get_port(self, context, id, fields=None): - """Get port. This method is delegated to the vswitch plugin. - - This method is included here to satisfy abstract method requirements. - """ - pass # pragma no cover - - def get_ports(self, context, filters=None, fields=None): - """Get ports. This method is delegated to the vswitch plugin. - - This method is included here to satisfy abstract method requirements. - """ - pass # pragma no cover - - def _check_nexus_net_create_needed(self, new_port, old_port): - """Check if nexus plugin should be invoked for net_create. - - In the following cases, the plugin should be invoked: - -- a port is attached to a VM instance. The old host id is None - -- VM migration. The old host id has a valid value - - When the plugin needs to be invoked, return the old_host_id, - and a list of calling arguments. - Otherwise, return '' for old host id and an empty list - """ - old_device_id = old_port['device_id'] - new_device_id = new_port.get('device_id') - new_host_id = self._get_port_host_id_from_bindings(new_port) - tenant_id = old_port['tenant_id'] - net_id = old_port['network_id'] - old_host_id = self._get_port_host_id_from_bindings(old_port) - - LOG.debug(_("tenant_id: %(tid)s, net_id: %(nid)s, " - "old_device_id: %(odi)s, new_device_id: %(ndi)s, " - "old_host_id: %(ohi)s, new_host_id: %(nhi)s, " - "old_device_owner: %(odo)s, new_device_owner: %(ndo)s"), - {'tid': tenant_id, 'nid': net_id, - 'odi': old_device_id, 'ndi': new_device_id, - 'ohi': old_host_id, 'nhi': new_host_id, - 'odo': old_port.get('device_owner'), - 'ndo': new_port.get('device_owner')}) - - # A port is attached to an instance - if (new_device_id and not old_device_id and new_host_id and - self._check_valid_port_device_owner(new_port)): - return '', [tenant_id, net_id, new_device_id, new_host_id] - - # An instance is being migrated - if (old_device_id and old_host_id and new_host_id != old_host_id and - self._check_valid_port_device_owner(old_port)): - return old_host_id, [tenant_id, net_id, old_device_id, new_host_id] - - # no need to invoke the plugin - return '', [] - - def update_port(self, context, id, port): - """Update port. - - Perform this operation in the context of the configured device - plugins. - """ - LOG.debug(_("update_port() called")) - old_port = self.get_port(context, id) - args = [context, id, port] - ovs_output = self._invoke_plugin_per_device(const.VSWITCH_PLUGIN, - self._func_name(), - args) - try: - # Check if the nexus plugin needs to be invoked - old_host_id, create_args = self._check_nexus_net_create_needed( - port['port'], old_port) - - # In the case of migration, invoke it to remove - # the previous port binding - if old_host_id: - vlan_id = self._get_segmentation_id(old_port['network_id']) - delete_args = [old_port['device_id'], vlan_id] - self._invoke_plugin_per_device(const.NEXUS_PLUGIN, - "delete_port", - delete_args) - - # Invoke the Nexus plugin to create a net and/or new port binding - if create_args: - self._invoke_nexus_for_net_create(context, *create_args) - - return ovs_output - except Exception: - exc_info = sys.exc_info() - LOG.error(_("Unable to update port '%s' on Nexus switch"), - old_port['name'], exc_info=exc_info) - try: - # Roll back vSwitch plugin to original port attributes. - args = [context, id, {'port': old_port}] - self._invoke_plugin_per_device( - const.VSWITCH_PLUGIN, - self._func_name(), - args) - finally: - # Re-raise the original exception - raise exc_info[0], exc_info[1], exc_info[2] - - def delete_port(self, context, id, l3_port_check=True): - """Delete port. - - Perform this operation in the context of the configured device - plugins. - """ - LOG.debug(_("delete_port() called")) - port = self.get_port(context, id) - - host_id = self._get_port_host_id_from_bindings(port) - - if (self.is_nexus_plugin and host_id and - self._check_valid_port_device_owner(port)): - vlan_id = self._get_segmentation_id(port['network_id']) - n_args = [port['device_id'], vlan_id] - self._invoke_plugin_per_device(const.NEXUS_PLUGIN, - self._func_name(), - n_args) - try: - args = [context, id] - ovs_output = self._invoke_plugin_per_device( - const.VSWITCH_PLUGIN, self._func_name(), - args, l3_port_check=l3_port_check) - except Exception: - exc_info = sys.exc_info() - # Roll back the delete port on the Nexus plugin - try: - tenant_id = port['tenant_id'] - net_id = port['network_id'] - instance_id = port['device_id'] - host_id = port[portbindings.HOST_ID] - self._invoke_nexus_for_net_create(context, tenant_id, net_id, - instance_id, host_id) - finally: - # Raise the original exception. - raise exc_info[0], exc_info[1], exc_info[2] - - return ovs_output - - def add_router_interface(self, context, router_id, interface_info): - """Add a router interface on a subnet. - - Only invoke the Nexus plugin to create SVI if L3 support on - the Nexus switches is enabled and a Nexus plugin is loaded, - otherwise send it to the vswitch plugin - """ - if (conf.CISCO.nexus_l3_enable and self.is_nexus_plugin): - LOG.debug(_("L3 enabled on Nexus plugin, create SVI on switch")) - if 'subnet_id' not in interface_info: - raise cexc.SubnetNotSpecified() - if 'port_id' in interface_info: - raise cexc.PortIdForNexusSvi() - subnet = self.get_subnet(context, interface_info['subnet_id']) - gateway_ip = subnet['gateway_ip'] - # Get gateway IP address and netmask - cidr = subnet['cidr'] - netmask = cidr.split('/', 1)[1] - gateway_ip = gateway_ip + '/' + netmask - network_id = subnet['network_id'] - vlan_id = self._get_segmentation_id(network_id) - vlan_name = conf.CISCO.vlan_name_prefix + str(vlan_id) - - n_args = [vlan_name, vlan_id, subnet['id'], gateway_ip, router_id] - return self._invoke_plugin_per_device(const.NEXUS_PLUGIN, - self._func_name(), - n_args) - else: - LOG.debug(_("L3 disabled or not Nexus plugin, send to vswitch")) - n_args = [context, router_id, interface_info] - return self._invoke_plugin_per_device(const.VSWITCH_PLUGIN, - self._func_name(), - n_args) - - def remove_router_interface(self, context, router_id, interface_info): - """Remove a router interface. - - Only invoke the Nexus plugin to delete SVI if L3 support on - the Nexus switches is enabled and a Nexus plugin is loaded, - otherwise send it to the vswitch plugin - """ - if (conf.CISCO.nexus_l3_enable and self.is_nexus_plugin): - LOG.debug(_("L3 enabled on Nexus plugin, delete SVI from switch")) - - subnet = self.get_subnet(context, interface_info['subnet_id']) - network_id = subnet['network_id'] - vlan_id = self._get_segmentation_id(network_id) - n_args = [vlan_id, router_id] - - return self._invoke_plugin_per_device(const.NEXUS_PLUGIN, - self._func_name(), - n_args) - else: - LOG.debug(_("L3 disabled or not Nexus plugin, send to vswitch")) - n_args = [context, router_id, interface_info] - return self._invoke_plugin_per_device(const.VSWITCH_PLUGIN, - self._func_name(), - n_args) - - def create_subnet(self, context, subnet): - """Create subnet. This method is delegated to the vswitch plugin. - - This method is included here to satisfy abstract method requirements. - """ - pass # pragma no cover - - def update_subnet(self, context, id, subnet): - """Update subnet. This method is delegated to the vswitch plugin. - - This method is included here to satisfy abstract method requirements. - """ - pass # pragma no cover - - def get_subnet(self, context, id, fields=None): - """Get subnet. This method is delegated to the vswitch plugin. - - This method is included here to satisfy abstract method requirements. - """ - pass # pragma no cover - - def delete_subnet(self, context, id, kwargs): - """Delete subnet. This method is delegated to the vswitch plugin. - - This method is included here to satisfy abstract method requirements. - """ - pass # pragma no cover - - def get_subnets(self, context, filters=None, fields=None, - sorts=None, limit=None, marker=None, page_reverse=False): - """Get subnets. This method is delegated to the vswitch plugin. - - This method is included here to satisfy abstract method requirements. - """ - pass # pragma no cover diff --git a/neutron/plugins/cisco/n1kv/__init__.py b/neutron/plugins/cisco/n1kv/__init__.py deleted file mode 100644 index 59a411933..000000000 --- a/neutron/plugins/cisco/n1kv/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cisco Systems, Inc. -# -# 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: Abhishek Raut, Cisco Systems, Inc. -# diff --git a/neutron/plugins/cisco/n1kv/n1kv_client.py b/neutron/plugins/cisco/n1kv/n1kv_client.py deleted file mode 100644 index 541750835..000000000 --- a/neutron/plugins/cisco/n1kv/n1kv_client.py +++ /dev/null @@ -1,541 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cisco Systems, Inc. -# -# 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: Abhishek Raut, Cisco Systems, Inc. -# @author: Rudrajit Tapadar, Cisco Systems, Inc. - -import base64 -import eventlet -import netaddr -import requests - -from neutron.common import exceptions as n_exc -from neutron.extensions import providernet -from neutron.openstack.common import jsonutils -from neutron.openstack.common import log as logging -from neutron.plugins.cisco.common import cisco_constants as c_const -from neutron.plugins.cisco.common import cisco_credentials_v2 as c_cred -from neutron.plugins.cisco.common import cisco_exceptions as c_exc -from neutron.plugins.cisco.common import config as c_conf -from neutron.plugins.cisco.db import network_db_v2 -from neutron.plugins.cisco.extensions import n1kv - -LOG = logging.getLogger(__name__) - - -class Client(object): - - """ - Client for the Cisco Nexus1000V Neutron Plugin. - - This client implements functions to communicate with - Cisco Nexus1000V VSM. - - For every Neutron objects, Cisco Nexus1000V Neutron Plugin - creates a corresponding object in the controller (Cisco - Nexus1000V VSM). - - CONCEPTS: - - Following are few concepts used in Nexus1000V VSM: - - port-profiles: - Policy profiles correspond to port profiles on Nexus1000V VSM. - Port profiles are the primary mechanism by which network policy is - defined and applied to switch interfaces in a Nexus 1000V system. - - network-segment: - Each network-segment represents a broadcast domain. - - network-segment-pool: - A network-segment-pool contains one or more network-segments. - - logical-network: - A logical-network contains one or more network-segment-pools. - - bridge-domain: - A bridge-domain is created when the network-segment is of type VXLAN. - Each VXLAN <--> VLAN combination can be thought of as a bridge domain. - - ip-pool: - Each ip-pool represents a subnet on the Nexus1000V VSM. - - vm-network: - vm-network refers to a network-segment and policy-profile. - It maintains a list of ports that uses the network-segment and - policy-profile this vm-network refers to. - - events: - Events correspond to commands that are logged on Nexus1000V VSM. - Events are used to poll for a certain resource on Nexus1000V VSM. - Event type of port_profile: Return all updates/create/deletes - of port profiles from the VSM. - Event type of port_profile_update: Return only updates regarding - policy-profiles. - Event type of port_profile_delete: Return only deleted policy profiles. - - - WORK FLOW: - - For every network profile a corresponding logical-network and - a network-segment-pool, under this logical-network, will be created. - - For every network created from a given network profile, a - network-segment will be added to the network-segment-pool corresponding - to that network profile. - - A port is created on a network and associated with a policy-profile. - Hence for every unique combination of a network and a policy-profile, a - unique vm-network will be created and a reference to the port will be - added. If the same combination of network and policy-profile is used by - another port, the references to that port will be added to the same - vm-network. - - - """ - - # Define paths for the URI where the client connects for HTTP requests. - port_profiles_path = "/virtual-port-profile" - network_segment_path = "/network-segment/%s" - network_segment_pool_path = "/network-segment-pool/%s" - ip_pool_path = "/ip-pool-template/%s" - ports_path = "/kvm/vm-network/%s/ports" - port_path = "/kvm/vm-network/%s/ports/%s" - vm_networks_path = "/kvm/vm-network" - vm_network_path = "/kvm/vm-network/%s" - bridge_domains_path = "/kvm/bridge-domain" - bridge_domain_path = "/kvm/bridge-domain/%s" - logical_network_path = "/logical-network/%s" - events_path = "/kvm/events" - clusters_path = "/cluster" - encap_profiles_path = "/encapsulation-profile" - encap_profile_path = "/encapsulation-profile/%s" - - pool = eventlet.GreenPool(c_conf.CISCO_N1K.http_pool_size) - - def __init__(self, **kwargs): - """Initialize a new client for the plugin.""" - self.format = 'json' - self.hosts = self._get_vsm_hosts() - self.action_prefix = 'http://%s/api/n1k' % self.hosts[0] - self.timeout = c_const.DEFAULT_HTTP_TIMEOUT - - def list_port_profiles(self): - """ - Fetch all policy profiles from the VSM. - - :returns: JSON string - """ - return self._get(self.port_profiles_path) - - def create_bridge_domain(self, network, overlay_subtype): - """ - Create a bridge domain on VSM. - - :param network: network dict - :param overlay_subtype: string representing subtype of overlay network - """ - body = {'name': network['id'] + c_const.BRIDGE_DOMAIN_SUFFIX, - 'segmentId': network[providernet.SEGMENTATION_ID], - 'subType': overlay_subtype, - 'tenantId': network['tenant_id']} - if overlay_subtype == c_const.NETWORK_SUBTYPE_NATIVE_VXLAN: - body['groupIp'] = network[n1kv.MULTICAST_IP] - return self._post(self.bridge_domains_path, - body=body) - - def delete_bridge_domain(self, name): - """ - Delete a bridge domain on VSM. - - :param name: name of the bridge domain to be deleted - """ - return self._delete(self.bridge_domain_path % name) - - def create_network_segment(self, network, network_profile): - """ - Create a network segment on the VSM. - - :param network: network dict - :param network_profile: network profile dict - """ - body = {'publishName': network['id'], - 'description': network['name'], - 'id': network['id'], - 'tenantId': network['tenant_id'], - 'networkSegmentPool': network_profile['id'], } - if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VLAN: - body['vlan'] = network[providernet.SEGMENTATION_ID] - elif network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_OVERLAY: - body['bridgeDomain'] = (network['id'] + - c_const.BRIDGE_DOMAIN_SUFFIX) - if network_profile['segment_type'] == c_const.NETWORK_TYPE_TRUNK: - body['mode'] = c_const.NETWORK_TYPE_TRUNK - body['segmentType'] = network_profile['sub_type'] - if network_profile['sub_type'] == c_const.NETWORK_TYPE_VLAN: - body['addSegments'] = network['add_segment_list'] - body['delSegments'] = network['del_segment_list'] - else: - body['encapProfile'] = (network['id'] + - c_const.ENCAPSULATION_PROFILE_SUFFIX) - else: - body['mode'] = 'access' - body['segmentType'] = network_profile['segment_type'] - return self._post(self.network_segment_path % network['id'], - body=body) - - def update_network_segment(self, network_segment_id, body): - """ - Update a network segment on the VSM. - - Network segment on VSM can be updated to associate it with an ip-pool - or update its description and segment id. - - :param network_segment_id: UUID representing the network segment - :param body: dict of arguments to be updated - """ - return self._post(self.network_segment_path % network_segment_id, - body=body) - - def delete_network_segment(self, network_segment_id): - """ - Delete a network segment on the VSM. - - :param network_segment_id: UUID representing the network segment - """ - return self._delete(self.network_segment_path % network_segment_id) - - def create_logical_network(self, network_profile, tenant_id): - """ - Create a logical network on the VSM. - - :param network_profile: network profile dict - :param tenant_id: UUID representing the tenant - """ - LOG.debug(_("Logical network")) - body = {'description': network_profile['name'], - 'tenantId': tenant_id} - logical_network_name = (network_profile['id'] + - c_const.LOGICAL_NETWORK_SUFFIX) - return self._post(self.logical_network_path % logical_network_name, - body=body) - - def delete_logical_network(self, logical_network_name): - """ - Delete a logical network on VSM. - - :param logical_network_name: string representing name of the logical - network - """ - return self._delete( - self.logical_network_path % logical_network_name) - - def create_network_segment_pool(self, network_profile, tenant_id): - """ - Create a network segment pool on the VSM. - - :param network_profile: network profile dict - :param tenant_id: UUID representing the tenant - """ - LOG.debug(_("network_segment_pool")) - logical_network_name = (network_profile['id'] + - c_const.LOGICAL_NETWORK_SUFFIX) - body = {'name': network_profile['name'], - 'description': network_profile['name'], - 'id': network_profile['id'], - 'logicalNetwork': logical_network_name, - 'tenantId': tenant_id} - return self._post( - self.network_segment_pool_path % network_profile['id'], - body=body) - - def update_network_segment_pool(self, network_profile): - """ - Update a network segment pool on the VSM. - - :param network_profile: network profile dict - """ - body = {'name': network_profile['name'], - 'description': network_profile['name']} - return self._post(self.network_segment_pool_path % - network_profile['id'], body=body) - - def delete_network_segment_pool(self, network_segment_pool_id): - """ - Delete a network segment pool on the VSM. - - :param network_segment_pool_id: UUID representing the network - segment pool - """ - return self._delete(self.network_segment_pool_path % - network_segment_pool_id) - - def create_ip_pool(self, subnet): - """ - Create an ip-pool on the VSM. - - :param subnet: subnet dict - """ - if subnet['cidr']: - try: - ip = netaddr.IPNetwork(subnet['cidr']) - netmask = str(ip.netmask) - network_address = str(ip.network) - except (ValueError, netaddr.AddrFormatError): - msg = _("Invalid input for CIDR") - raise n_exc.InvalidInput(error_message=msg) - else: - netmask = network_address = "" - - if subnet['allocation_pools']: - address_range_start = subnet['allocation_pools'][0]['start'] - address_range_end = subnet['allocation_pools'][0]['end'] - else: - address_range_start = None - address_range_end = None - - body = {'addressRangeStart': address_range_start, - 'addressRangeEnd': address_range_end, - 'ipAddressSubnet': netmask, - 'description': subnet['name'], - 'gateway': subnet['gateway_ip'], - 'dhcp': subnet['enable_dhcp'], - 'dnsServersList': subnet['dns_nameservers'], - 'networkAddress': network_address, - 'tenantId': subnet['tenant_id']} - return self._post(self.ip_pool_path % subnet['id'], - body=body) - - def update_ip_pool(self, subnet): - """ - Update an ip-pool on the VSM. - - :param subnet: subnet dictionary - """ - body = {'description': subnet['name'], - 'dhcp': subnet['enable_dhcp'], - 'dnsServersList': subnet['dns_nameservers']} - return self._post(self.ip_pool_path % subnet['id'], - body=body) - - def delete_ip_pool(self, subnet_id): - """ - Delete an ip-pool on the VSM. - - :param subnet_id: UUID representing the subnet - """ - return self._delete(self.ip_pool_path % subnet_id) - - def create_vm_network(self, - port, - vm_network_name, - policy_profile): - """ - Create a VM network on the VSM. - - :param port: port dict - :param vm_network_name: name of the VM network - :param policy_profile: policy profile dict - """ - body = {'name': vm_network_name, - 'networkSegmentId': port['network_id'], - 'networkSegment': port['network_id'], - 'portProfile': policy_profile['name'], - 'portProfileId': policy_profile['id'], - 'tenantId': port['tenant_id'], - 'portId': port['id'], - 'macAddress': port['mac_address'], - } - if port.get('fixed_ips'): - body['ipAddress'] = port['fixed_ips'][0]['ip_address'] - body['subnetId'] = port['fixed_ips'][0]['subnet_id'] - return self._post(self.vm_networks_path, - body=body) - - def delete_vm_network(self, vm_network_name): - """ - Delete a VM network on the VSM. - - :param vm_network_name: name of the VM network - """ - return self._delete(self.vm_network_path % vm_network_name) - - def create_n1kv_port(self, port, vm_network_name): - """ - Create a port on the VSM. - - :param port: port dict - :param vm_network_name: name of the VM network which imports this port - """ - body = {'id': port['id'], - 'macAddress': port['mac_address']} - if port.get('fixed_ips'): - body['ipAddress'] = port['fixed_ips'][0]['ip_address'] - body['subnetId'] = port['fixed_ips'][0]['subnet_id'] - return self._post(self.ports_path % vm_network_name, - body=body) - - def update_n1kv_port(self, vm_network_name, port_id, body): - """ - Update a port on the VSM. - - Update the mac address associated with the port - - :param vm_network_name: name of the VM network which imports this port - :param port_id: UUID of the port - :param body: dict of the arguments to be updated - """ - return self._post(self.port_path % (vm_network_name, port_id), - body=body) - - def delete_n1kv_port(self, vm_network_name, port_id): - """ - Delete a port on the VSM. - - :param vm_network_name: name of the VM network which imports this port - :param port_id: UUID of the port - """ - return self._delete(self.port_path % (vm_network_name, port_id)) - - def _do_request(self, method, action, body=None, - headers=None): - """ - Perform the HTTP request. - - The response is in either JSON format or plain text. A GET method will - invoke a JSON response while a PUT/POST/DELETE returns message from the - VSM in plain text format. - Exception is raised when VSM replies with an INTERNAL SERVER ERROR HTTP - status code (500) i.e. an error has occurred on the VSM or SERVICE - UNAVAILABLE (503) i.e. VSM is not reachable. - - :param method: type of the HTTP request. POST, GET, PUT or DELETE - :param action: path to which the client makes request - :param body: dict for arguments which are sent as part of the request - :param headers: header for the HTTP request - :returns: JSON or plain text in HTTP response - """ - action = self.action_prefix + action - if not headers and self.hosts: - headers = self._get_auth_header(self.hosts[0]) - headers['Content-Type'] = self._set_content_type('json') - headers['Accept'] = self._set_content_type('json') - if body: - body = jsonutils.dumps(body, indent=2) - LOG.debug(_("req: %s"), body) - try: - resp = self.pool.spawn(requests.request, - method, - url=action, - data=body, - headers=headers, - timeout=self.timeout).wait() - except Exception as e: - raise c_exc.VSMConnectionFailed(reason=e) - LOG.debug(_("status_code %s"), resp.status_code) - if resp.status_code == requests.codes.OK: - if 'application/json' in resp.headers['content-type']: - try: - return resp.json() - except ValueError: - return {} - elif 'text/plain' in resp.headers['content-type']: - LOG.debug(_("VSM: %s"), resp.text) - else: - raise c_exc.VSMError(reason=resp.text) - - def _set_content_type(self, format=None): - """ - Set the mime-type to either 'xml' or 'json'. - - :param format: format to be set. - :return: mime-type string - """ - if not format: - format = self.format - return "application/%s" % format - - def _delete(self, action, body=None, headers=None): - return self._do_request("DELETE", action, body=body, - headers=headers) - - def _get(self, action, body=None, headers=None): - return self._do_request("GET", action, body=body, - headers=headers) - - def _post(self, action, body=None, headers=None): - return self._do_request("POST", action, body=body, - headers=headers) - - def _put(self, action, body=None, headers=None): - return self._do_request("PUT", action, body=body, - headers=headers) - - def _get_vsm_hosts(self): - """ - Retrieve a list of VSM ip addresses. - - :return: list of host ip addresses - """ - return [cr[c_const.CREDENTIAL_NAME] for cr in - network_db_v2.get_all_n1kv_credentials()] - - def _get_auth_header(self, host_ip): - """ - Retrieve header with auth info for the VSM. - - :param host_ip: IP address of the VSM - :return: authorization header dict - """ - username = c_cred.Store.get_username(host_ip) - password = c_cred.Store.get_password(host_ip) - auth = base64.encodestring("%s:%s" % (username, password)).rstrip() - header = {"Authorization": "Basic %s" % auth} - return header - - def get_clusters(self): - """Fetches a list of all vxlan gateway clusters.""" - return self._get(self.clusters_path) - - def create_encapsulation_profile(self, encap): - """ - Create an encapsulation profile on VSM. - - :param encap: encapsulation dict - """ - body = {'name': encap['name'], - 'addMappings': encap['add_segment_list'], - 'delMappings': encap['del_segment_list']} - return self._post(self.encap_profiles_path, - body=body) - - def update_encapsulation_profile(self, context, profile_name, body): - """ - Adds a vlan to bridge-domain mapping to an encapsulation profile. - - :param profile_name: Name of the encapsulation profile - :param body: mapping dictionary - """ - return self._post(self.encap_profile_path - % profile_name, body=body) - - def delete_encapsulation_profile(self, name): - """ - Delete an encapsulation profile on VSM. - - :param name: name of the encapsulation profile to be deleted - """ - return self._delete(self.encap_profile_path % name) diff --git a/neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py b/neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py deleted file mode 100644 index 6ef51f3d0..000000000 --- a/neutron/plugins/cisco/n1kv/n1kv_neutron_plugin.py +++ /dev/null @@ -1,1438 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cisco Systems, Inc. -# -# 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: Aruna Kushwaha, Cisco Systems, Inc. -# @author: Rudrajit Tapadar, Cisco Systems, Inc. -# @author: Abhishek Raut, Cisco Systems, Inc. -# @author: Sergey Sudakovich, Cisco Systems, Inc. - -import eventlet - -from oslo.config import cfg as q_conf - -from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api -from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api -from neutron.api.v2 import attributes -from neutron.common import constants -from neutron.common import exceptions as n_exc -from neutron.common import rpc_compat -from neutron.common import topics -from neutron.common import utils -from neutron.db import agents_db -from neutron.db import agentschedulers_db -from neutron.db import db_base_plugin_v2 -from neutron.db import dhcp_rpc_base -from neutron.db import external_net_db -from neutron.db import extraroute_db -from neutron.db import l3_agentschedulers_db -from neutron.db import l3_rpc_base -from neutron.db import portbindings_db -from neutron.extensions import portbindings -from neutron.extensions import providernet -from neutron.openstack.common import importutils -from neutron.openstack.common import log as logging -from neutron.openstack.common import uuidutils as uuidutils -from neutron.plugins.cisco.common import cisco_constants as c_const -from neutron.plugins.cisco.common import cisco_credentials_v2 as c_cred -from neutron.plugins.cisco.common import cisco_exceptions -from neutron.plugins.cisco.common import config as c_conf -from neutron.plugins.cisco.db import n1kv_db_v2 -from neutron.plugins.cisco.db import network_db_v2 -from neutron.plugins.cisco.extensions import n1kv -from neutron.plugins.cisco.n1kv import n1kv_client -from neutron.plugins.common import constants as svc_constants - - -LOG = logging.getLogger(__name__) - - -class N1kvRpcCallbacks(rpc_compat.RpcCallback, - dhcp_rpc_base.DhcpRpcCallbackMixin, - l3_rpc_base.L3RpcCallbackMixin): - - """Class to handle agent RPC calls.""" - - # Set RPC API version to 1.1 by default. - RPC_API_VERSION = '1.1' - - -class N1kvNeutronPluginV2(db_base_plugin_v2.NeutronDbPluginV2, - external_net_db.External_net_db_mixin, - extraroute_db.ExtraRoute_db_mixin, - portbindings_db.PortBindingMixin, - n1kv_db_v2.NetworkProfile_db_mixin, - n1kv_db_v2.PolicyProfile_db_mixin, - network_db_v2.Credential_db_mixin, - l3_agentschedulers_db.L3AgentSchedulerDbMixin, - agentschedulers_db.DhcpAgentSchedulerDbMixin): - - """ - Implement the Neutron abstractions using Cisco Nexus1000V. - - Refer README file for the architecture, new features, and - workflow - - """ - - # This attribute specifies whether the plugin supports or not - # bulk operations. - __native_bulk_support = False - supported_extension_aliases = ["provider", "agent", - "n1kv", "network_profile", - "policy_profile", "external-net", "router", - "binding", "credential", - "l3_agent_scheduler", - "dhcp_agent_scheduler"] - - def __init__(self, configfile=None): - """ - Initialize Nexus1000V Neutron plugin. - - 1. Initialize VIF type to OVS - 2. Initialize Nexus1000v and Credential DB - 3. Establish communication with Cisco Nexus1000V - """ - super(N1kvNeutronPluginV2, self).__init__() - self.base_binding_dict = { - portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS, - portbindings.VIF_DETAILS: { - # TODO(rkukura): Replace with new VIF security details - portbindings.CAP_PORT_FILTER: - 'security-group' in self.supported_extension_aliases}} - c_cred.Store.initialize() - self._setup_vsm() - self._setup_rpc() - self.network_scheduler = importutils.import_object( - q_conf.CONF.network_scheduler_driver - ) - self.router_scheduler = importutils.import_object( - q_conf.CONF.router_scheduler_driver - ) - - def _setup_rpc(self): - # RPC support - self.service_topics = {svc_constants.CORE: topics.PLUGIN, - svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN} - self.conn = rpc_compat.create_connection(new=True) - self.endpoints = [N1kvRpcCallbacks(), agents_db.AgentExtRpcCallback()] - for svc_topic in self.service_topics.values(): - self.conn.create_consumer(svc_topic, self.endpoints, fanout=False) - self.dhcp_agent_notifier = dhcp_rpc_agent_api.DhcpAgentNotifyAPI() - self.l3_agent_notifier = l3_rpc_agent_api.L3AgentNotifyAPI() - # Consume from all consumers in threads - self.conn.consume_in_threads() - - def _setup_vsm(self): - """ - Setup Cisco Nexus 1000V related parameters and pull policy profiles. - - Retrieve all the policy profiles from the VSM when the plugin is - is instantiated for the first time and then continue to poll for - policy profile updates. - """ - LOG.debug(_('_setup_vsm')) - self.agent_vsm = True - # Poll VSM for create/delete of policy profile. - eventlet.spawn(self._poll_policy_profiles) - - def _poll_policy_profiles(self): - """Start a green thread to pull policy profiles from VSM.""" - while True: - self._populate_policy_profiles() - eventlet.sleep(c_conf.CISCO_N1K.poll_duration) - - def _populate_policy_profiles(self): - """ - Populate all the policy profiles from VSM. - - The tenant id is not available when the policy profiles are polled - from the VSM. Hence we associate the policy profiles with fake - tenant-ids. - """ - LOG.debug(_('_populate_policy_profiles')) - try: - n1kvclient = n1kv_client.Client() - policy_profiles = n1kvclient.list_port_profiles() - vsm_profiles = {} - plugin_profiles_set = set() - # Fetch policy profiles from VSM - for profile_name in policy_profiles: - profile_id = (policy_profiles - [profile_name][c_const.PROPERTIES][c_const.ID]) - vsm_profiles[profile_id] = profile_name - # Fetch policy profiles previously populated - for profile in n1kv_db_v2.get_policy_profiles(): - plugin_profiles_set.add(profile.id) - vsm_profiles_set = set(vsm_profiles) - # Update database if the profile sets differ. - if vsm_profiles_set ^ plugin_profiles_set: - # Add profiles in database if new profiles were created in VSM - for pid in vsm_profiles_set - plugin_profiles_set: - self._add_policy_profile(vsm_profiles[pid], pid) - - # Delete profiles from database if profiles were deleted in VSM - for pid in plugin_profiles_set - vsm_profiles_set: - self._delete_policy_profile(pid) - self._remove_all_fake_policy_profiles() - except (cisco_exceptions.VSMError, - cisco_exceptions.VSMConnectionFailed): - LOG.warning(_('No policy profile populated from VSM')) - - def _extend_network_dict_provider(self, context, network): - """Add extended network parameters.""" - binding = n1kv_db_v2.get_network_binding(context.session, - network['id']) - network[providernet.NETWORK_TYPE] = binding.network_type - if binding.network_type == c_const.NETWORK_TYPE_OVERLAY: - network[providernet.PHYSICAL_NETWORK] = None - network[providernet.SEGMENTATION_ID] = binding.segmentation_id - network[n1kv.MULTICAST_IP] = binding.multicast_ip - elif binding.network_type == c_const.NETWORK_TYPE_VLAN: - network[providernet.PHYSICAL_NETWORK] = binding.physical_network - network[providernet.SEGMENTATION_ID] = binding.segmentation_id - elif binding.network_type == c_const.NETWORK_TYPE_TRUNK: - network[providernet.PHYSICAL_NETWORK] = binding.physical_network - network[providernet.SEGMENTATION_ID] = None - network[n1kv.MULTICAST_IP] = None - elif binding.network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT: - network[providernet.PHYSICAL_NETWORK] = None - network[providernet.SEGMENTATION_ID] = None - network[n1kv.MULTICAST_IP] = None - - def _process_provider_create(self, context, attrs): - network_type = attrs.get(providernet.NETWORK_TYPE) - physical_network = attrs.get(providernet.PHYSICAL_NETWORK) - segmentation_id = attrs.get(providernet.SEGMENTATION_ID) - - network_type_set = attributes.is_attr_set(network_type) - physical_network_set = attributes.is_attr_set(physical_network) - segmentation_id_set = attributes.is_attr_set(segmentation_id) - - if not (network_type_set or physical_network_set or - segmentation_id_set): - return (None, None, None) - - if not network_type_set: - msg = _("provider:network_type required") - raise n_exc.InvalidInput(error_message=msg) - elif network_type == c_const.NETWORK_TYPE_VLAN: - if not segmentation_id_set: - msg = _("provider:segmentation_id required") - raise n_exc.InvalidInput(error_message=msg) - if segmentation_id < 1 or segmentation_id > 4094: - msg = _("provider:segmentation_id out of range " - "(1 through 4094)") - raise n_exc.InvalidInput(error_message=msg) - elif network_type == c_const.NETWORK_TYPE_OVERLAY: - if physical_network_set: - msg = _("provider:physical_network specified for Overlay " - "network") - raise n_exc.InvalidInput(error_message=msg) - else: - physical_network = None - if not segmentation_id_set: - msg = _("provider:segmentation_id required") - raise n_exc.InvalidInput(error_message=msg) - if segmentation_id < 5000: - msg = _("provider:segmentation_id out of range " - "(5000+)") - raise n_exc.InvalidInput(error_message=msg) - else: - msg = _("provider:network_type %s not supported"), network_type - raise n_exc.InvalidInput(error_message=msg) - - if network_type == c_const.NETWORK_TYPE_VLAN: - if physical_network_set: - network_profiles = n1kv_db_v2.get_network_profiles() - for network_profile in network_profiles: - if physical_network == network_profile[ - 'physical_network']: - break - else: - msg = (_("Unknown provider:physical_network %s"), - physical_network) - raise n_exc.InvalidInput(error_message=msg) - else: - msg = _("provider:physical_network required") - raise n_exc.InvalidInput(error_message=msg) - - return (network_type, physical_network, segmentation_id) - - def _check_provider_update(self, context, attrs): - """Handle Provider network updates.""" - network_type = attrs.get(providernet.NETWORK_TYPE) - physical_network = attrs.get(providernet.PHYSICAL_NETWORK) - segmentation_id = attrs.get(providernet.SEGMENTATION_ID) - - network_type_set = attributes.is_attr_set(network_type) - physical_network_set = attributes.is_attr_set(physical_network) - segmentation_id_set = attributes.is_attr_set(segmentation_id) - - if not (network_type_set or physical_network_set or - segmentation_id_set): - return - - # TBD : Need to handle provider network updates - msg = _("Plugin does not support updating provider attributes") - raise n_exc.InvalidInput(error_message=msg) - - def _get_cluster(self, segment1, segment2, clusters): - """ - Returns a cluster to apply the segment mapping - - :param segment1: UUID of segment to be mapped - :param segment2: UUID of segment to be mapped - :param clusters: List of clusters - """ - for cluster in sorted(clusters, key=lambda k: k['size']): - for mapping in cluster[c_const.MAPPINGS]: - for segment in mapping[c_const.SEGMENTS]: - if segment1 in segment or segment2 in segment: - break - else: - cluster['size'] += 2 - return cluster['encapProfileName'] - break - return - - def _extend_mapping_dict(self, context, mapping_dict, segment): - """ - Extend a mapping dictionary with dot1q tag and bridge-domain name. - - :param context: neutron api request context - :param mapping_dict: dictionary to populate values - :param segment: id of the segment being populated - """ - net = self.get_network(context, segment) - if net[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_VLAN: - mapping_dict['dot1q'] = str(net[providernet.SEGMENTATION_ID]) - else: - mapping_dict['bridgeDomain'] = (net['name'] + - c_const.BRIDGE_DOMAIN_SUFFIX) - - def _send_add_multi_segment_request(self, context, net_id, segment_pairs): - """ - Send Add multi-segment network request to VSM. - - :param context: neutron api request context - :param net_id: UUID of the multi-segment network - :param segment_pairs: List of segments in UUID pairs - that need to be bridged - """ - - if not segment_pairs: - return - - session = context.session - n1kvclient = n1kv_client.Client() - clusters = n1kvclient.get_clusters() - online_clusters = [] - encap_dict = {} - for cluster in clusters['body'][c_const.SET]: - cluster = cluster[c_const.PROPERTIES] - if cluster[c_const.STATE] == c_const.ONLINE: - cluster['size'] = 0 - for mapping in cluster[c_const.MAPPINGS]: - cluster['size'] += ( - len(mapping[c_const.SEGMENTS])) - online_clusters.append(cluster) - for (segment1, segment2) in segment_pairs: - encap_profile = self._get_cluster(segment1, segment2, - online_clusters) - if encap_profile is not None: - if encap_profile in encap_dict: - profile_dict = encap_dict[encap_profile] - else: - profile_dict = {'name': encap_profile, - 'addMappings': [], - 'delMappings': []} - encap_dict[encap_profile] = profile_dict - mapping_dict = {} - self._extend_mapping_dict(context, - mapping_dict, segment1) - self._extend_mapping_dict(context, - mapping_dict, segment2) - profile_dict['addMappings'].append(mapping_dict) - n1kv_db_v2.add_multi_segment_encap_profile_name(session, - net_id, - (segment1, - segment2), - encap_profile) - else: - raise cisco_exceptions.NoClusterFound - - for profile in encap_dict: - n1kvclient.update_encapsulation_profile(context, profile, - encap_dict[profile]) - - def _send_del_multi_segment_request(self, context, net_id, segment_pairs): - """ - Send Delete multi-segment network request to VSM. - - :param context: neutron api request context - :param net_id: UUID of the multi-segment network - :param segment_pairs: List of segments in UUID pairs - whose bridging needs to be removed - """ - if not segment_pairs: - return - session = context.session - encap_dict = {} - n1kvclient = n1kv_client.Client() - for (segment1, segment2) in segment_pairs: - binding = ( - n1kv_db_v2.get_multi_segment_network_binding(session, net_id, - (segment1, - segment2))) - encap_profile = binding['encap_profile_name'] - if encap_profile in encap_dict: - profile_dict = encap_dict[encap_profile] - else: - profile_dict = {'name': encap_profile, - 'addMappings': [], - 'delMappings': []} - encap_dict[encap_profile] = profile_dict - mapping_dict = {} - self._extend_mapping_dict(context, - mapping_dict, segment1) - self._extend_mapping_dict(context, - mapping_dict, segment2) - profile_dict['delMappings'].append(mapping_dict) - - for profile in encap_dict: - n1kvclient.update_encapsulation_profile(context, profile, - encap_dict[profile]) - - def _get_encap_segments(self, context, segment_pairs): - """ - Get the list of segments in encapsulation profile format. - - :param context: neutron api request context - :param segment_pairs: List of segments that need to be bridged - """ - member_list = [] - for pair in segment_pairs: - (segment, dot1qtag) = pair - member_dict = {} - net = self.get_network(context, segment) - member_dict['bridgeDomain'] = (net['name'] + - c_const.BRIDGE_DOMAIN_SUFFIX) - member_dict['dot1q'] = dot1qtag - member_list.append(member_dict) - return member_list - - def _populate_member_segments(self, context, network, segment_pairs, oper): - """ - Populate trunk network dict with member segments. - - :param context: neutron api request context - :param network: Dictionary containing the trunk network information - :param segment_pairs: List of segments in UUID pairs - that needs to be trunked - :param oper: Operation to be performed - """ - LOG.debug(_('_populate_member_segments %s'), segment_pairs) - trunk_list = [] - for (segment, dot1qtag) in segment_pairs: - net = self.get_network(context, segment) - member_dict = {'segment': net['name'], - 'dot1qtag': dot1qtag} - trunk_list.append(member_dict) - if oper == n1kv.SEGMENT_ADD: - network['add_segment_list'] = trunk_list - elif oper == n1kv.SEGMENT_DEL: - network['del_segment_list'] = trunk_list - - def _parse_multi_segments(self, context, attrs, param): - """ - Parse the multi-segment network attributes. - - :param context: neutron api request context - :param attrs: Attributes of the network - :param param: Additional parameter indicating an add - or del operation - :returns: List of segment UUIDs in set pairs - """ - pair_list = [] - valid_seg_types = [c_const.NETWORK_TYPE_VLAN, - c_const.NETWORK_TYPE_OVERLAY] - segments = attrs.get(param) - if not attributes.is_attr_set(segments): - return pair_list - for pair in segments.split(','): - segment1, sep, segment2 = pair.partition(':') - if (uuidutils.is_uuid_like(segment1) and - uuidutils.is_uuid_like(segment2)): - binding1 = n1kv_db_v2.get_network_binding(context.session, - segment1) - binding2 = n1kv_db_v2.get_network_binding(context.session, - segment2) - if (binding1.network_type not in valid_seg_types or - binding2.network_type not in valid_seg_types or - binding1.network_type == binding2.network_type): - msg = _("Invalid pairing supplied") - raise n_exc.InvalidInput(error_message=msg) - else: - pair_list.append((segment1, segment2)) - else: - LOG.debug(_('Invalid UUID supplied in %s'), pair) - msg = _("Invalid UUID supplied") - raise n_exc.InvalidInput(error_message=msg) - return pair_list - - def _parse_trunk_segments(self, context, attrs, param, physical_network, - sub_type): - """ - Parse the trunk network attributes. - - :param context: neutron api request context - :param attrs: Attributes of the network - :param param: Additional parameter indicating an add - or del operation - :param physical_network: Physical network of the trunk segment - :param sub_type: Sub-type of the trunk segment - :returns: List of segment UUIDs and dot1qtag (for vxlan) in set pairs - """ - pair_list = [] - segments = attrs.get(param) - if not attributes.is_attr_set(segments): - return pair_list - for pair in segments.split(','): - segment, sep, dot1qtag = pair.partition(':') - if sub_type == c_const.NETWORK_TYPE_VLAN: - dot1qtag = '' - if uuidutils.is_uuid_like(segment): - binding = n1kv_db_v2.get_network_binding(context.session, - segment) - if binding.network_type == c_const.NETWORK_TYPE_TRUNK: - msg = _("Cannot add a trunk segment '%s' as a member of " - "another trunk segment") % segment - raise n_exc.InvalidInput(error_message=msg) - elif binding.network_type == c_const.NETWORK_TYPE_VLAN: - if sub_type == c_const.NETWORK_TYPE_OVERLAY: - msg = _("Cannot add vlan segment '%s' as a member of " - "a vxlan trunk segment") % segment - raise n_exc.InvalidInput(error_message=msg) - if not physical_network: - physical_network = binding.physical_network - elif physical_network != binding.physical_network: - msg = _("Network UUID '%s' belongs to a different " - "physical network") % segment - raise n_exc.InvalidInput(error_message=msg) - elif binding.network_type == c_const.NETWORK_TYPE_OVERLAY: - if sub_type == c_const.NETWORK_TYPE_VLAN: - msg = _("Cannot add vxlan segment '%s' as a member of " - "a vlan trunk segment") % segment - raise n_exc.InvalidInput(error_message=msg) - try: - if not utils.is_valid_vlan_tag(int(dot1qtag)): - msg = _("Vlan tag '%s' is out of range") % dot1qtag - raise n_exc.InvalidInput(error_message=msg) - except ValueError: - msg = _("Vlan tag '%s' is not an integer " - "value") % dot1qtag - raise n_exc.InvalidInput(error_message=msg) - pair_list.append((segment, dot1qtag)) - else: - LOG.debug(_('%s is not a valid uuid'), segment) - msg = _("'%s' is not a valid UUID") % segment - raise n_exc.InvalidInput(error_message=msg) - return pair_list - - def _extend_network_dict_member_segments(self, context, network): - """Add the extended parameter member segments to the network.""" - members = [] - binding = n1kv_db_v2.get_network_binding(context.session, - network['id']) - if binding.network_type == c_const.NETWORK_TYPE_TRUNK: - members = n1kv_db_v2.get_trunk_members(context.session, - network['id']) - elif binding.network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT: - members = n1kv_db_v2.get_multi_segment_members(context.session, - network['id']) - network[n1kv.MEMBER_SEGMENTS] = members - - def _extend_network_dict_profile(self, context, network): - """Add the extended parameter network profile to the network.""" - binding = n1kv_db_v2.get_network_binding(context.session, - network['id']) - network[n1kv.PROFILE_ID] = binding.profile_id - - def _extend_port_dict_profile(self, context, port): - """Add the extended parameter port profile to the port.""" - binding = n1kv_db_v2.get_port_binding(context.session, - port['id']) - port[n1kv.PROFILE_ID] = binding.profile_id - - def _process_network_profile(self, context, network): - """Validate network profile exists.""" - profile_id = network.get(n1kv.PROFILE_ID) - profile_id_set = attributes.is_attr_set(profile_id) - if not profile_id_set: - profile_name = c_conf.CISCO_N1K.default_network_profile - net_p = self._get_network_profile_by_name(context.session, - profile_name) - profile_id = net_p['id'] - network['n1kv:profile_id'] = profile_id - return profile_id - - def _process_policy_profile(self, context, attrs): - """Validates whether policy profile exists.""" - profile_id = attrs.get(n1kv.PROFILE_ID) - profile_id_set = attributes.is_attr_set(profile_id) - if not profile_id_set: - msg = _("n1kv:profile_id does not exist") - raise n_exc.InvalidInput(error_message=msg) - if not self._policy_profile_exists(profile_id): - msg = _("n1kv:profile_id does not exist") - raise n_exc.InvalidInput(error_message=msg) - - return profile_id - - def _send_create_logical_network_request(self, network_profile, tenant_id): - """ - Send create logical network request to VSM. - - :param network_profile: network profile dictionary - :param tenant_id: UUID representing the tenant - """ - LOG.debug(_('_send_create_logical_network')) - n1kvclient = n1kv_client.Client() - n1kvclient.create_logical_network(network_profile, tenant_id) - - def _send_delete_logical_network_request(self, network_profile): - """ - Send delete logical network request to VSM. - - :param network_profile: network profile dictionary - """ - LOG.debug('_send_delete_logical_network') - n1kvclient = n1kv_client.Client() - logical_network_name = (network_profile['id'] + - c_const.LOGICAL_NETWORK_SUFFIX) - n1kvclient.delete_logical_network(logical_network_name) - - def _send_create_network_profile_request(self, context, profile): - """ - Send create network profile request to VSM. - - :param context: neutron api request context - :param profile: network profile dictionary - """ - LOG.debug(_('_send_create_network_profile_request: %s'), profile['id']) - n1kvclient = n1kv_client.Client() - n1kvclient.create_network_segment_pool(profile, context.tenant_id) - - def _send_update_network_profile_request(self, profile): - """ - Send update network profile request to VSM. - - :param profile: network profile dictionary - """ - LOG.debug(_('_send_update_network_profile_request: %s'), profile['id']) - n1kvclient = n1kv_client.Client() - n1kvclient.update_network_segment_pool(profile) - - def _send_delete_network_profile_request(self, profile): - """ - Send delete network profile request to VSM. - - :param profile: network profile dictionary - """ - LOG.debug(_('_send_delete_network_profile_request: %s'), - profile['name']) - n1kvclient = n1kv_client.Client() - n1kvclient.delete_network_segment_pool(profile['id']) - - def _send_create_network_request(self, context, network, segment_pairs): - """ - Send create network request to VSM. - - Create a bridge domain for network of type Overlay. - :param context: neutron api request context - :param network: network dictionary - :param segment_pairs: List of segments in UUID pairs - that need to be bridged - """ - LOG.debug(_('_send_create_network_request: %s'), network['id']) - profile = self.get_network_profile(context, - network[n1kv.PROFILE_ID]) - n1kvclient = n1kv_client.Client() - if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_OVERLAY: - n1kvclient.create_bridge_domain(network, profile['sub_type']) - if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_TRUNK: - self._populate_member_segments(context, network, segment_pairs, - n1kv.SEGMENT_ADD) - network['del_segment_list'] = [] - if profile['sub_type'] == c_const.NETWORK_TYPE_OVERLAY: - encap_dict = {'name': (network['name'] + - c_const.ENCAPSULATION_PROFILE_SUFFIX), - 'add_segment_list': ( - self._get_encap_segments(context, - segment_pairs)), - 'del_segment_list': []} - n1kvclient.create_encapsulation_profile(encap_dict) - n1kvclient.create_network_segment(network, profile) - - def _send_update_network_request(self, context, network, add_segments, - del_segments): - """ - Send update network request to VSM. - - :param context: neutron api request context - :param network: network dictionary - :param add_segments: List of segments bindings - that need to be deleted - :param del_segments: List of segments bindings - that need to be deleted - """ - LOG.debug(_('_send_update_network_request: %s'), network['id']) - db_session = context.session - profile = n1kv_db_v2.get_network_profile( - db_session, network[n1kv.PROFILE_ID]) - n1kvclient = n1kv_client.Client() - body = {'description': network['name'], - 'id': network['id'], - 'networkSegmentPool': profile['id'], - 'vlan': network[providernet.SEGMENTATION_ID], - 'mode': 'access', - 'segmentType': profile['segment_type'], - 'addSegments': [], - 'delSegments': []} - if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_TRUNK: - self._populate_member_segments(context, network, add_segments, - n1kv.SEGMENT_ADD) - self._populate_member_segments(context, network, del_segments, - n1kv.SEGMENT_DEL) - body['mode'] = c_const.NETWORK_TYPE_TRUNK - body['segmentType'] = profile['sub_type'] - body['addSegments'] = network['add_segment_list'] - body['delSegments'] = network['del_segment_list'] - LOG.debug(_('add_segments=%s'), body['addSegments']) - LOG.debug(_('del_segments=%s'), body['delSegments']) - if profile['sub_type'] == c_const.NETWORK_TYPE_OVERLAY: - encap_profile = (network['id'] + - c_const.ENCAPSULATION_PROFILE_SUFFIX) - encap_dict = {'name': encap_profile, - 'addMappings': ( - self._get_encap_segments(context, - add_segments)), - 'delMappings': ( - self._get_encap_segments(context, - del_segments))} - n1kvclient.update_encapsulation_profile(context, encap_profile, - encap_dict) - n1kvclient.update_network_segment(network['id'], body) - - def _send_delete_network_request(self, context, network): - """ - Send delete network request to VSM. - - Delete bridge domain if network is of type Overlay. - Delete encapsulation profile if network is of type OVERLAY Trunk. - :param context: neutron api request context - :param network: network dictionary - """ - LOG.debug(_('_send_delete_network_request: %s'), network['id']) - n1kvclient = n1kv_client.Client() - session = context.session - if network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_OVERLAY: - name = network['id'] + c_const.BRIDGE_DOMAIN_SUFFIX - n1kvclient.delete_bridge_domain(name) - elif network[providernet.NETWORK_TYPE] == c_const.NETWORK_TYPE_TRUNK: - profile = self.get_network_profile( - context, network[n1kv.PROFILE_ID]) - if profile['sub_type'] == c_const.NETWORK_TYPE_OVERLAY: - profile_name = (network['id'] + - c_const.ENCAPSULATION_PROFILE_SUFFIX) - n1kvclient.delete_encapsulation_profile(profile_name) - elif (network[providernet.NETWORK_TYPE] == - c_const.NETWORK_TYPE_MULTI_SEGMENT): - encap_dict = n1kv_db_v2.get_multi_segment_encap_dict(session, - network['id']) - for profile in encap_dict: - profile_dict = {'name': profile, - 'addSegments': [], - 'delSegments': []} - for segment_pair in encap_dict[profile]: - mapping_dict = {} - (segment1, segment2) = segment_pair - self._extend_mapping_dict(context, - mapping_dict, segment1) - self._extend_mapping_dict(context, - mapping_dict, segment2) - profile_dict['delSegments'].append(mapping_dict) - n1kvclient.update_encapsulation_profile(context, profile, - profile_dict) - n1kvclient.delete_network_segment(network['id']) - - def _send_create_subnet_request(self, context, subnet): - """ - Send create subnet request to VSM. - - :param context: neutron api request context - :param subnet: subnet dictionary - """ - LOG.debug(_('_send_create_subnet_request: %s'), subnet['id']) - n1kvclient = n1kv_client.Client() - n1kvclient.create_ip_pool(subnet) - - def _send_update_subnet_request(self, subnet): - """ - Send update subnet request to VSM. - - :param subnet: subnet dictionary - """ - LOG.debug(_('_send_update_subnet_request: %s'), subnet['name']) - n1kvclient = n1kv_client.Client() - n1kvclient.update_ip_pool(subnet) - - def _send_delete_subnet_request(self, context, subnet): - """ - Send delete subnet request to VSM. - - :param context: neutron api request context - :param subnet: subnet dictionary - """ - LOG.debug(_('_send_delete_subnet_request: %s'), subnet['name']) - body = {'ipPool': subnet['id'], 'deleteSubnet': True} - n1kvclient = n1kv_client.Client() - n1kvclient.update_network_segment(subnet['network_id'], body=body) - n1kvclient.delete_ip_pool(subnet['id']) - - def _send_create_port_request(self, - context, - port, - port_count, - policy_profile, - vm_network_name): - """ - Send create port request to VSM. - - Create a VM network for a network and policy profile combination. - If the VM network already exists, bind this port to the existing - VM network on the VSM. - :param context: neutron api request context - :param port: port dictionary - :param port_count: integer representing the number of ports in one - VM Network - :param policy_profile: object of type policy profile - :param vm_network_name: string representing the name of the VM - network - """ - LOG.debug(_('_send_create_port_request: %s'), port) - n1kvclient = n1kv_client.Client() - if port_count == 1: - n1kvclient.create_vm_network(port, - vm_network_name, - policy_profile) - else: - n1kvclient.create_n1kv_port(port, vm_network_name) - - def _send_update_port_request(self, port_id, mac_address, vm_network_name): - """ - Send update port request to VSM. - - :param port_id: UUID representing port to update - :param mac_address: string representing the mac address - :param vm_network_name: VM network name to which the port is bound - """ - LOG.debug(_('_send_update_port_request: %s'), port_id) - body = {'portId': port_id, - 'macAddress': mac_address} - n1kvclient = n1kv_client.Client() - n1kvclient.update_n1kv_port(vm_network_name, port_id, body) - - def _send_delete_port_request(self, context, port, vm_network): - """ - Send delete port request to VSM. - - Delete the port on the VSM. If it is the last port on the VM Network, - delete the VM Network. - :param context: neutron api request context - :param port: port object which is to be deleted - :param vm_network: VM network object with which the port is associated - """ - LOG.debug(_('_send_delete_port_request: %s'), port['id']) - n1kvclient = n1kv_client.Client() - n1kvclient.delete_n1kv_port(vm_network['name'], port['id']) - if vm_network['port_count'] == 0: - n1kvclient.delete_vm_network(vm_network['name']) - - def _get_segmentation_id(self, context, id): - """ - Retrieve segmentation ID for a given network. - - :param context: neutron api request context - :param id: UUID of the network - :returns: segmentation ID for the network - """ - session = context.session - binding = n1kv_db_v2.get_network_binding(session, id) - return binding.segmentation_id - - def create_network(self, context, network): - """ - Create network based on network profile. - - :param context: neutron api request context - :param network: network dictionary - :returns: network object - """ - (network_type, physical_network, - segmentation_id) = self._process_provider_create(context, - network['network']) - profile_id = self._process_network_profile(context, network['network']) - segment_pairs = None - LOG.debug(_('Create network: profile_id=%s'), profile_id) - session = context.session - with session.begin(subtransactions=True): - if not network_type: - # tenant network - (physical_network, network_type, segmentation_id, - multicast_ip) = n1kv_db_v2.alloc_network(session, - profile_id) - LOG.debug(_('Physical_network %(phy_net)s, ' - 'seg_type %(net_type)s, ' - 'seg_id %(seg_id)s, ' - 'multicast_ip %(multicast_ip)s'), - {'phy_net': physical_network, - 'net_type': network_type, - 'seg_id': segmentation_id, - 'multicast_ip': multicast_ip}) - if network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT: - segment_pairs = ( - self._parse_multi_segments(context, network['network'], - n1kv.SEGMENT_ADD)) - LOG.debug(_('Seg list %s '), segment_pairs) - elif network_type == c_const.NETWORK_TYPE_TRUNK: - network_profile = self.get_network_profile(context, - profile_id) - segment_pairs = ( - self._parse_trunk_segments(context, network['network'], - n1kv.SEGMENT_ADD, - physical_network, - network_profile['sub_type'] - )) - LOG.debug(_('Seg list %s '), segment_pairs) - else: - if not segmentation_id: - raise n_exc.TenantNetworksDisabled() - else: - # provider network - if network_type == c_const.NETWORK_TYPE_VLAN: - network_profile = self.get_network_profile(context, - profile_id) - seg_min, seg_max = self._get_segment_range( - network_profile['segment_range']) - if not seg_min <= segmentation_id <= seg_max: - raise cisco_exceptions.VlanIDOutsidePool - n1kv_db_v2.reserve_specific_vlan(session, - physical_network, - segmentation_id) - multicast_ip = "0.0.0.0" - net = super(N1kvNeutronPluginV2, self).create_network(context, - network) - n1kv_db_v2.add_network_binding(session, - net['id'], - network_type, - physical_network, - segmentation_id, - multicast_ip, - profile_id, - segment_pairs) - self._process_l3_create(context, net, network['network']) - self._extend_network_dict_provider(context, net) - self._extend_network_dict_profile(context, net) - try: - if network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT: - self._send_add_multi_segment_request(context, net['id'], - segment_pairs) - else: - self._send_create_network_request(context, net, segment_pairs) - except(cisco_exceptions.VSMError, - cisco_exceptions.VSMConnectionFailed): - super(N1kvNeutronPluginV2, self).delete_network(context, net['id']) - else: - LOG.debug(_("Created network: %s"), net['id']) - return net - - def update_network(self, context, id, network): - """ - Update network parameters. - - :param context: neutron api request context - :param id: UUID representing the network to update - :returns: updated network object - """ - self._check_provider_update(context, network['network']) - add_segments = [] - del_segments = [] - - session = context.session - with session.begin(subtransactions=True): - net = super(N1kvNeutronPluginV2, self).update_network(context, id, - network) - self._process_l3_update(context, net, network['network']) - binding = n1kv_db_v2.get_network_binding(session, id) - if binding.network_type == c_const.NETWORK_TYPE_MULTI_SEGMENT: - add_segments = ( - self._parse_multi_segments(context, network['network'], - n1kv.SEGMENT_ADD)) - n1kv_db_v2.add_multi_segment_binding(session, - net['id'], add_segments) - del_segments = ( - self._parse_multi_segments(context, network['network'], - n1kv.SEGMENT_DEL)) - self._send_add_multi_segment_request(context, net['id'], - add_segments) - self._send_del_multi_segment_request(context, net['id'], - del_segments) - n1kv_db_v2.del_multi_segment_binding(session, - net['id'], del_segments) - elif binding.network_type == c_const.NETWORK_TYPE_TRUNK: - network_profile = self.get_network_profile(context, - binding.profile_id) - add_segments = ( - self._parse_trunk_segments(context, network['network'], - n1kv.SEGMENT_ADD, - binding.physical_network, - network_profile['sub_type'])) - n1kv_db_v2.add_trunk_segment_binding(session, - net['id'], add_segments) - del_segments = ( - self._parse_trunk_segments(context, network['network'], - n1kv.SEGMENT_DEL, - binding.physical_network, - network_profile['sub_type'])) - n1kv_db_v2.del_trunk_segment_binding(session, - net['id'], del_segments) - self._extend_network_dict_provider(context, net) - self._extend_network_dict_profile(context, net) - if binding.network_type != c_const.NETWORK_TYPE_MULTI_SEGMENT: - self._send_update_network_request(context, net, add_segments, - del_segments) - LOG.debug(_("Updated network: %s"), net['id']) - return net - - def delete_network(self, context, id): - """ - Delete a network. - - :param context: neutron api request context - :param id: UUID representing the network to delete - """ - session = context.session - with session.begin(subtransactions=True): - binding = n1kv_db_v2.get_network_binding(session, id) - network = self.get_network(context, id) - if n1kv_db_v2.is_trunk_member(session, id): - msg = _("Cannot delete network '%s' " - "that is member of a trunk segment") % network['name'] - raise n_exc.InvalidInput(error_message=msg) - if n1kv_db_v2.is_multi_segment_member(session, id): - msg = _("Cannot delete network '%s' that is a member of a " - "multi-segment network") % network['name'] - raise n_exc.InvalidInput(error_message=msg) - if binding.network_type == c_const.NETWORK_TYPE_OVERLAY: - n1kv_db_v2.release_vxlan(session, binding.segmentation_id) - elif binding.network_type == c_const.NETWORK_TYPE_VLAN: - n1kv_db_v2.release_vlan(session, binding.physical_network, - binding.segmentation_id) - self._process_l3_delete(context, id) - super(N1kvNeutronPluginV2, self).delete_network(context, id) - # the network_binding record is deleted via cascade from - # the network record, so explicit removal is not necessary - self._send_delete_network_request(context, network) - LOG.debug(_("Deleted network: %s"), id) - - def get_network(self, context, id, fields=None): - """ - Retrieve a Network. - - :param context: neutron api request context - :param id: UUID representing the network to fetch - :returns: requested network dictionary - """ - LOG.debug(_("Get network: %s"), id) - net = super(N1kvNeutronPluginV2, self).get_network(context, id, None) - self._extend_network_dict_provider(context, net) - self._extend_network_dict_profile(context, net) - self._extend_network_dict_member_segments(context, net) - return self._fields(net, fields) - - def get_networks(self, context, filters=None, fields=None): - """ - Retrieve a list of networks. - - :param context: neutron api request context - :param filters: a dictionary with keys that are valid keys for a - network object. Values in this dictiontary are an - iterable containing values that will be used for an - exact match comparison for that value. Each result - returned by this function will have matched one of the - values for each key in filters - :params fields: a list of strings that are valid keys in a network - dictionary. Only these fields will be returned. - :returns: list of network dictionaries. - """ - LOG.debug(_("Get networks")) - nets = super(N1kvNeutronPluginV2, self).get_networks(context, filters, - None) - for net in nets: - self._extend_network_dict_provider(context, net) - self._extend_network_dict_profile(context, net) - - return [self._fields(net, fields) for net in nets] - - def create_port(self, context, port): - """ - Create neutron port. - - Create a port. Use a default policy profile for ports created for dhcp - and router interface. Default policy profile name is configured in the - /etc/neutron/cisco_plugins.ini file. - - :param context: neutron api request context - :param port: port dictionary - :returns: port object - """ - p_profile = None - port_count = None - vm_network_name = None - profile_id_set = False - - # Set the network policy profile id for auto generated L3/DHCP ports - if ('device_id' in port['port'] and port['port']['device_owner'] in - [constants.DEVICE_OWNER_DHCP, constants.DEVICE_OWNER_ROUTER_INTF, - constants.DEVICE_OWNER_ROUTER_GW, - constants.DEVICE_OWNER_FLOATINGIP]): - p_profile_name = c_conf.CISCO_N1K.network_node_policy_profile - p_profile = self._get_policy_profile_by_name(p_profile_name) - if p_profile: - port['port']['n1kv:profile_id'] = p_profile['id'] - - if n1kv.PROFILE_ID in port['port']: - profile_id = port['port'].get(n1kv.PROFILE_ID) - profile_id_set = attributes.is_attr_set(profile_id) - - # Set the default policy profile id for ports if no id is set - if not profile_id_set: - p_profile_name = c_conf.CISCO_N1K.default_policy_profile - p_profile = self._get_policy_profile_by_name(p_profile_name) - if p_profile: - port['port']['n1kv:profile_id'] = p_profile['id'] - profile_id_set = True - - profile_id = self._process_policy_profile(context, - port['port']) - LOG.debug(_('Create port: profile_id=%s'), profile_id) - session = context.session - with session.begin(subtransactions=True): - pt = super(N1kvNeutronPluginV2, self).create_port(context, - port) - n1kv_db_v2.add_port_binding(session, pt['id'], profile_id) - self._extend_port_dict_profile(context, pt) - try: - vm_network = n1kv_db_v2.get_vm_network( - context.session, - profile_id, - pt['network_id']) - except cisco_exceptions.VMNetworkNotFound: - # Create a VM Network if no VM network exists. - vm_network_name = "%s%s_%s" % (c_const.VM_NETWORK_NAME_PREFIX, - profile_id, - pt['network_id']) - port_count = 1 - n1kv_db_v2.add_vm_network(context.session, - vm_network_name, - profile_id, - pt['network_id'], - port_count) - else: - # Update port count of the VM network. - vm_network_name = vm_network['name'] - port_count = vm_network['port_count'] + 1 - n1kv_db_v2.update_vm_network_port_count(context.session, - vm_network_name, - port_count) - self._process_portbindings_create_and_update(context, - port['port'], - pt) - # Extract policy profile for VM network create in VSM. - if not p_profile: - p_profile = n1kv_db_v2.get_policy_profile(session, profile_id) - try: - self._send_create_port_request(context, - pt, - port_count, - p_profile, - vm_network_name) - except(cisco_exceptions.VSMError, - cisco_exceptions.VSMConnectionFailed): - super(N1kvNeutronPluginV2, self).delete_port(context, pt['id']) - else: - LOG.debug(_("Created port: %s"), pt) - return pt - - def update_port(self, context, id, port): - """ - Update port parameters. - - :param context: neutron api request context - :param id: UUID representing the port to update - :returns: updated port object - """ - LOG.debug(_("Update port: %s"), id) - with context.session.begin(subtransactions=True): - updated_port = super(N1kvNeutronPluginV2, - self).update_port(context, id, port) - self._process_portbindings_create_and_update(context, - port['port'], - updated_port) - self._extend_port_dict_profile(context, updated_port) - return updated_port - - def delete_port(self, context, id, l3_port_check=True): - """ - Delete a port. - - :param context: neutron api request context - :param id: UUID representing the port to delete - """ - # if needed, check to see if this is a port owned by - # and l3-router. If so, we should prevent deletion. - if l3_port_check: - self.prevent_l3_port_deletion(context, id) - with context.session.begin(subtransactions=True): - port = self.get_port(context, id) - vm_network = n1kv_db_v2.get_vm_network(context.session, - port[n1kv.PROFILE_ID], - port['network_id']) - vm_network['port_count'] -= 1 - n1kv_db_v2.update_vm_network_port_count(context.session, - vm_network['name'], - vm_network['port_count']) - if vm_network['port_count'] == 0: - n1kv_db_v2.delete_vm_network(context.session, - port[n1kv.PROFILE_ID], - port['network_id']) - self.disassociate_floatingips(context, id) - super(N1kvNeutronPluginV2, self).delete_port(context, id) - self._send_delete_port_request(context, port, vm_network) - - def get_port(self, context, id, fields=None): - """ - Retrieve a port. - :param context: neutron api request context - :param id: UUID representing the port to retrieve - :param fields: a list of strings that are valid keys in a port - dictionary. Only these fields will be returned. - :returns: port dictionary - """ - LOG.debug(_("Get port: %s"), id) - port = super(N1kvNeutronPluginV2, self).get_port(context, id, None) - self._extend_port_dict_profile(context, port) - return self._fields(port, fields) - - def get_ports(self, context, filters=None, fields=None): - """ - Retrieve a list of ports. - - :param context: neutron api request context - :param filters: a dictionary with keys that are valid keys for a - port object. Values in this dictiontary are an - iterable containing values that will be used for an - exact match comparison for that value. Each result - returned by this function will have matched one of the - values for each key in filters - :params fields: a list of strings that are valid keys in a port - dictionary. Only these fields will be returned. - :returns: list of port dictionaries - """ - LOG.debug(_("Get ports")) - ports = super(N1kvNeutronPluginV2, self).get_ports(context, filters, - None) - for port in ports: - self._extend_port_dict_profile(context, port) - - return [self._fields(port, fields) for port in ports] - - def create_subnet(self, context, subnet): - """ - Create subnet for a given network. - - :param context: neutron api request context - :param subnet: subnet dictionary - :returns: subnet object - """ - LOG.debug(_('Create subnet')) - sub = super(N1kvNeutronPluginV2, self).create_subnet(context, subnet) - try: - self._send_create_subnet_request(context, sub) - except(cisco_exceptions.VSMError, - cisco_exceptions.VSMConnectionFailed): - super(N1kvNeutronPluginV2, self).delete_subnet(context, sub['id']) - else: - LOG.debug(_("Created subnet: %s"), sub['id']) - return sub - - def update_subnet(self, context, id, subnet): - """ - Update a subnet. - - :param context: neutron api request context - :param id: UUID representing subnet to update - :returns: updated subnet object - """ - LOG.debug(_('Update subnet')) - sub = super(N1kvNeutronPluginV2, self).update_subnet(context, - id, - subnet) - self._send_update_subnet_request(sub) - return sub - - def delete_subnet(self, context, id): - """ - Delete a subnet. - - :param context: neutron api request context - :param id: UUID representing subnet to delete - :returns: deleted subnet object - """ - LOG.debug(_('Delete subnet: %s'), id) - subnet = self.get_subnet(context, id) - self._send_delete_subnet_request(context, subnet) - return super(N1kvNeutronPluginV2, self).delete_subnet(context, id) - - def get_subnet(self, context, id, fields=None): - """ - Retrieve a subnet. - - :param context: neutron api request context - :param id: UUID representing subnet to retrieve - :params fields: a list of strings that are valid keys in a subnet - dictionary. Only these fields will be returned. - :returns: subnet object - """ - LOG.debug(_("Get subnet: %s"), id) - subnet = super(N1kvNeutronPluginV2, self).get_subnet(context, id, - None) - return self._fields(subnet, fields) - - def get_subnets(self, context, filters=None, fields=None): - """ - Retrieve a list of subnets. - - :param context: neutron api request context - :param filters: a dictionary with keys that are valid keys for a - subnet object. Values in this dictiontary are an - iterable containing values that will be used for an - exact match comparison for that value. Each result - returned by this function will have matched one of the - values for each key in filters - :params fields: a list of strings that are valid keys in a subnet - dictionary. Only these fields will be returned. - :returns: list of dictionaries of subnets - """ - LOG.debug(_("Get subnets")) - subnets = super(N1kvNeutronPluginV2, self).get_subnets(context, - filters, - None) - return [self._fields(subnet, fields) for subnet in subnets] - - def create_network_profile(self, context, network_profile): - """ - Create a network profile. - - Create a network profile, which represents a pool of networks - belonging to one type (VLAN or Overlay). On creation of network - profile, we retrieve the admin tenant-id which we use to replace - the previously stored fake tenant-id in tenant-profile bindings. - :param context: neutron api request context - :param network_profile: network profile dictionary - :returns: network profile object - """ - self._replace_fake_tenant_id_with_real(context) - with context.session.begin(subtransactions=True): - net_p = super(N1kvNeutronPluginV2, - self).create_network_profile(context, - network_profile) - try: - self._send_create_logical_network_request(net_p, - context.tenant_id) - except(cisco_exceptions.VSMError, - cisco_exceptions.VSMConnectionFailed): - n1kv_db_v2.delete_profile_binding(context.session, - context.tenant_id, - net_p['id']) - try: - self._send_create_network_profile_request(context, net_p) - except(cisco_exceptions.VSMError, - cisco_exceptions.VSMConnectionFailed): - n1kv_db_v2.delete_profile_binding(context.session, - context.tenant_id, - net_p['id']) - self._send_delete_logical_network_request(net_p) - return net_p - - def delete_network_profile(self, context, id): - """ - Delete a network profile. - - :param context: neutron api request context - :param id: UUID of the network profile to delete - :returns: deleted network profile object - """ - with context.session.begin(subtransactions=True): - net_p = super(N1kvNeutronPluginV2, - self).delete_network_profile(context, id) - self._send_delete_network_profile_request(net_p) - self._send_delete_logical_network_request(net_p) - - def update_network_profile(self, context, net_profile_id, network_profile): - """ - Update a network profile. - - :param context: neutron api request context - :param net_profile_id: UUID of the network profile to update - :param network_profile: dictionary containing network profile object - """ - session = context.session - with session.begin(subtransactions=True): - net_p = (super(N1kvNeutronPluginV2, self). - update_network_profile(context, - net_profile_id, - network_profile)) - self._send_update_network_profile_request(net_p) - return net_p - - def create_router(self, context, router): - """ - Handle creation of router. - - Schedule router to L3 agent as part of the create handling. - :param context: neutron api request context - :param router: router dictionary - :returns: router object - """ - session = context.session - with session.begin(subtransactions=True): - rtr = (super(N1kvNeutronPluginV2, self). - create_router(context, router)) - LOG.debug(_("Scheduling router %s"), rtr['id']) - self.schedule_router(context, rtr['id']) - return rtr diff --git a/neutron/plugins/cisco/network_plugin.py b/neutron/plugins/cisco/network_plugin.py deleted file mode 100644 index ee35fec81..000000000 --- a/neutron/plugins/cisco/network_plugin.py +++ /dev/null @@ -1,176 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012 Cisco Systems, Inc. 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: Sumit Naiksatam, Cisco Systems, Inc. - -import logging - -import webob.exc as wexc - -from neutron.api import extensions as neutron_extensions -from neutron.api.v2 import base -from neutron.db import db_base_plugin_v2 -from neutron.openstack.common import importutils -from neutron.plugins.cisco.common import cisco_exceptions as cexc -from neutron.plugins.cisco.common import config -from neutron.plugins.cisco.db import network_db_v2 as cdb -from neutron.plugins.cisco import extensions - -LOG = logging.getLogger(__name__) - - -class PluginV2(db_base_plugin_v2.NeutronDbPluginV2): - """Meta-Plugin with v2 API support for multiple sub-plugins.""" - _supported_extension_aliases = ["credential", "Cisco qos"] - _methods_to_delegate = ['create_network', - 'delete_network', 'update_network', 'get_network', - 'get_networks', - 'create_port', 'delete_port', - 'update_port', 'get_port', 'get_ports', - 'create_subnet', - 'delete_subnet', 'update_subnet', - 'get_subnet', 'get_subnets', ] - - CISCO_FAULT_MAP = { - cexc.CredentialAlreadyExists: wexc.HTTPBadRequest, - cexc.CredentialNameNotFound: wexc.HTTPNotFound, - cexc.CredentialNotFound: wexc.HTTPNotFound, - cexc.NetworkSegmentIDNotFound: wexc.HTTPNotFound, - cexc.NetworkVlanBindingAlreadyExists: wexc.HTTPBadRequest, - cexc.NexusComputeHostNotConfigured: wexc.HTTPNotFound, - cexc.NexusConfigFailed: wexc.HTTPBadRequest, - cexc.NexusConnectFailed: wexc.HTTPServiceUnavailable, - cexc.NexusPortBindingNotFound: wexc.HTTPNotFound, - cexc.NoMoreNics: wexc.HTTPBadRequest, - cexc.PortIdForNexusSvi: wexc.HTTPBadRequest, - cexc.PortVnicBindingAlreadyExists: wexc.HTTPBadRequest, - cexc.PortVnicNotFound: wexc.HTTPNotFound, - cexc.QosNameAlreadyExists: wexc.HTTPBadRequest, - cexc.QosNotFound: wexc.HTTPNotFound, - cexc.SubnetNotSpecified: wexc.HTTPBadRequest, - cexc.VlanIDNotAvailable: wexc.HTTPNotFound, - cexc.VlanIDNotFound: wexc.HTTPNotFound, - } - - @property - def supported_extension_aliases(self): - if not hasattr(self, '_aliases'): - aliases = self._supported_extension_aliases[:] - if hasattr(self._model, "supported_extension_aliases"): - aliases.extend(self._model.supported_extension_aliases) - self._aliases = aliases - return self._aliases - - def __init__(self): - """Load the model class.""" - self._model_name = config.CISCO.model_class - self._model = importutils.import_object(self._model_name) - native_bulk_attr_name = ("_%s__native_bulk_support" - % self._model.__class__.__name__) - self.__native_bulk_support = getattr(self._model, - native_bulk_attr_name, False) - - neutron_extensions.append_api_extensions_path(extensions.__path__) - - # Extend the fault map - self._extend_fault_map() - - LOG.debug(_("Plugin initialization complete")) - - def __getattribute__(self, name): - """Delegate core API calls to the model class. - - Core API calls are delegated directly to the configured model class. - Note: Bulking calls will be handled by this class, and turned into - non-bulking calls to be considered for delegation. - """ - methods = object.__getattribute__(self, "_methods_to_delegate") - if name in methods: - return getattr(object.__getattribute__(self, "_model"), - name) - else: - return object.__getattribute__(self, name) - - def __getattr__(self, name): - """Delegate calls to the extensions. - - This delegates the calls to the extensions explicitly implemented by - the model. - """ - if hasattr(self._model, name): - return getattr(self._model, name) - else: - # Must make sure we re-raise the error that led us here, since - # otherwise getattr() and even hasattr() doesn't work correctly. - raise AttributeError( - _("'%(model)s' object has no attribute '%(name)s'") % - {'model': self._model_name, 'name': name}) - - def _extend_fault_map(self): - """Extend the Neutron Fault Map for Cisco exceptions. - - Map exceptions which are specific to the Cisco Plugin - to standard HTTP exceptions. - - """ - base.FAULT_MAP.update(self.CISCO_FAULT_MAP) - - """ - Extension API implementation - """ - def get_all_qoss(self, tenant_id): - """Get all QoS levels.""" - LOG.debug(_("get_all_qoss() called")) - qoslist = cdb.get_all_qoss(tenant_id) - return qoslist - - def get_qos_details(self, tenant_id, qos_id): - """Get QoS Details.""" - LOG.debug(_("get_qos_details() called")) - return cdb.get_qos(tenant_id, qos_id) - - def create_qos(self, tenant_id, qos_name, qos_desc): - """Create a QoS level.""" - LOG.debug(_("create_qos() called")) - qos = cdb.add_qos(tenant_id, qos_name, str(qos_desc)) - return qos - - def delete_qos(self, tenant_id, qos_id): - """Delete a QoS level.""" - LOG.debug(_("delete_qos() called")) - return cdb.remove_qos(tenant_id, qos_id) - - def rename_qos(self, tenant_id, qos_id, new_name): - """Rename QoS level.""" - LOG.debug(_("rename_qos() called")) - return cdb.update_qos(tenant_id, qos_id, new_name) - - def get_all_credentials(self): - """Get all credentials.""" - LOG.debug(_("get_all_credentials() called")) - credential_list = cdb.get_all_credentials() - return credential_list - - def get_credential_details(self, credential_id): - """Get a particular credential.""" - LOG.debug(_("get_credential_details() called")) - return cdb.get_credential(credential_id) - - def rename_credential(self, credential_id, new_name, new_password): - """Rename the particular credential resource.""" - LOG.debug(_("rename_credential() called")) - return cdb.update_credential(credential_id, new_name, - new_password=new_password) diff --git a/neutron/plugins/cisco/nexus/__init__.py b/neutron/plugins/cisco/nexus/__init__.py deleted file mode 100644 index 963eb547f..000000000 --- a/neutron/plugins/cisco/nexus/__init__.py +++ /dev/null @@ -1,21 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 Cisco Systems, Inc. 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: Sumit Naiksatam, Cisco Systems, Inc. -# @author: Edgar Magana, Cisco Systems, Inc. -""" -Init module for Nexus Driver -""" diff --git a/neutron/plugins/cisco/nexus/cisco_nexus_network_driver_v2.py b/neutron/plugins/cisco/nexus/cisco_nexus_network_driver_v2.py deleted file mode 100644 index bef145f03..000000000 --- a/neutron/plugins/cisco/nexus/cisco_nexus_network_driver_v2.py +++ /dev/null @@ -1,196 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 Cisco Systems, Inc. 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: Debojyoti Dutta, Cisco Systems, Inc. -# @author: Edgar Magana, Cisco Systems Inc. -# -""" -Implements a Nexus-OS NETCONF over SSHv2 API Client -""" - -import logging - -from ncclient import manager - -from neutron.openstack.common import excutils -from neutron.plugins.cisco.common import cisco_constants as const -from neutron.plugins.cisco.common import cisco_credentials_v2 as cred -from neutron.plugins.cisco.common import cisco_exceptions as cexc -from neutron.plugins.cisco.common import config as conf -from neutron.plugins.cisco.db import nexus_db_v2 -from neutron.plugins.cisco.nexus import cisco_nexus_snippets as snipp - -LOG = logging.getLogger(__name__) - - -class CiscoNEXUSDriver(): - """Nexus Driver Main Class.""" - def __init__(self): - cisco_switches = conf.get_device_dictionary() - self.nexus_switches = dict(((key[1], key[2]), val) - for key, val in cisco_switches.items() - if key[0] == 'NEXUS_SWITCH') - self.credentials = {} - self.connections = {} - - def _edit_config(self, nexus_host, target='running', config='', - allowed_exc_strs=None): - """Modify switch config for a target config type. - - :param nexus_host: IP address of switch to configure - :param target: Target config type - :param config: Configuration string in XML format - :param allowed_exc_strs: Exceptions which have any of these strings - as a subset of their exception message - (str(exception)) can be ignored - - :raises: NexusConfigFailed - - """ - if not allowed_exc_strs: - allowed_exc_strs = [] - mgr = self.nxos_connect(nexus_host) - try: - mgr.edit_config(target, config=config) - except Exception as e: - for exc_str in allowed_exc_strs: - if exc_str in str(e): - break - else: - # Raise a Neutron exception. Include a description of - # the original ncclient exception. No need to preserve T/B - raise cexc.NexusConfigFailed(config=config, exc=e) - - def get_credential(self, nexus_ip): - if nexus_ip not in self.credentials: - nexus_username = cred.Store.get_username(nexus_ip) - nexus_password = cred.Store.get_password(nexus_ip) - self.credentials[nexus_ip] = { - const.USERNAME: nexus_username, - const.PASSWORD: nexus_password - } - return self.credentials[nexus_ip] - - def nxos_connect(self, nexus_host): - """Make SSH connection to the Nexus Switch.""" - if getattr(self.connections.get(nexus_host), 'connected', None): - return self.connections[nexus_host] - - nexus_ssh_port = int(self.nexus_switches[nexus_host, 'ssh_port']) - nexus_creds = self.get_credential(nexus_host) - nexus_user = nexus_creds[const.USERNAME] - nexus_password = nexus_creds[const.PASSWORD] - try: - man = manager.connect(host=nexus_host, - port=nexus_ssh_port, - username=nexus_user, - password=nexus_password) - self.connections[nexus_host] = man - except Exception as e: - # Raise a Neutron exception. Include a description of - # the original ncclient exception. No need to preserve T/B. - raise cexc.NexusConnectFailed(nexus_host=nexus_host, exc=e) - - return self.connections[nexus_host] - - def create_xml_snippet(self, cutomized_config): - """Create XML snippet. - - Creates the Proper XML structure for the Nexus Switch Configuration. - """ - conf_xml_snippet = snipp.EXEC_CONF_SNIPPET % (cutomized_config) - return conf_xml_snippet - - def create_vlan(self, nexus_host, vlanid, vlanname): - """Create a VLAN on Nexus Switch given the VLAN ID and Name.""" - confstr = self.create_xml_snippet( - snipp.CMD_VLAN_CONF_SNIPPET % (vlanid, vlanname)) - self._edit_config(nexus_host, target='running', config=confstr) - - # Enable VLAN active and no-shutdown states. Some versions of - # Nexus switch do not allow state changes for the extended VLAN - # range (1006-4094), but these errors can be ignored (default - # values are appropriate). - state_config = [snipp.CMD_VLAN_ACTIVE_SNIPPET, - snipp.CMD_VLAN_NO_SHUTDOWN_SNIPPET] - for snippet in state_config: - try: - confstr = self.create_xml_snippet(snippet % vlanid) - self._edit_config( - nexus_host, - target='running', - config=confstr, - allowed_exc_strs=["Can't modify state for extended", - "Command is only allowed on VLAN"]) - except cexc.NexusConfigFailed: - with excutils.save_and_reraise_exception(): - self.delete_vlan(nexus_host, vlanid) - - def delete_vlan(self, nexus_host, vlanid): - """Delete a VLAN on Nexus Switch given the VLAN ID.""" - confstr = snipp.CMD_NO_VLAN_CONF_SNIPPET % vlanid - confstr = self.create_xml_snippet(confstr) - self._edit_config(nexus_host, target='running', config=confstr) - - def enable_vlan_on_trunk_int(self, nexus_host, vlanid, etype, interface): - """Enable a VLAN on a trunk interface.""" - # If one or more VLANs are already configured on this interface, - # include the 'add' keyword. - if nexus_db_v2.get_port_switch_bindings('%s:%s' % (etype, interface), - nexus_host): - snippet = snipp.CMD_INT_VLAN_ADD_SNIPPET - else: - snippet = snipp.CMD_INT_VLAN_SNIPPET - confstr = snippet % (etype, interface, vlanid, etype) - confstr = self.create_xml_snippet(confstr) - LOG.debug(_("NexusDriver: %s"), confstr) - self._edit_config(nexus_host, target='running', config=confstr) - - def disable_vlan_on_trunk_int(self, nexus_host, vlanid, etype, interface): - """Disable a VLAN on a trunk interface.""" - confstr = snipp.CMD_NO_VLAN_INT_SNIPPET % (etype, interface, - vlanid, etype) - confstr = self.create_xml_snippet(confstr) - LOG.debug(_("NexusDriver: %s"), confstr) - self._edit_config(nexus_host, target='running', config=confstr) - - def create_and_trunk_vlan(self, nexus_host, vlan_id, vlan_name, - etype, nexus_port): - """Create VLAN and trunk it on the specified ports.""" - self.create_vlan(nexus_host, vlan_id, vlan_name) - LOG.debug(_("NexusDriver created VLAN: %s"), vlan_id) - if nexus_port: - self.enable_vlan_on_trunk_int(nexus_host, vlan_id, - etype, nexus_port) - - def delete_and_untrunk_vlan(self, nexus_host, vlan_id, etype, nexus_port): - """Delete VLAN and untrunk it from the specified ports.""" - self.delete_vlan(nexus_host, vlan_id) - if nexus_port: - self.disable_vlan_on_trunk_int(nexus_host, vlan_id, - etype, nexus_port) - - def create_vlan_svi(self, nexus_host, vlan_id, gateway_ip): - confstr = snipp.CMD_VLAN_SVI_SNIPPET % (vlan_id, gateway_ip) - confstr = self.create_xml_snippet(confstr) - LOG.debug(_("NexusDriver: %s"), confstr) - self._edit_config(nexus_host, target='running', config=confstr) - - def delete_vlan_svi(self, nexus_host, vlan_id): - confstr = snipp.CMD_NO_VLAN_SVI_SNIPPET % vlan_id - confstr = self.create_xml_snippet(confstr) - LOG.debug(_("NexusDriver: %s"), confstr) - self._edit_config(nexus_host, target='running', config=confstr) diff --git a/neutron/plugins/cisco/nexus/cisco_nexus_plugin_v2.py b/neutron/plugins/cisco/nexus/cisco_nexus_plugin_v2.py deleted file mode 100644 index e9e34811a..000000000 --- a/neutron/plugins/cisco/nexus/cisco_nexus_plugin_v2.py +++ /dev/null @@ -1,347 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012 Cisco Systems, Inc. -# 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: Sumit Naiksatam, Cisco Systems, Inc. -# @author: Edgar Magana, Cisco Systems, Inc. -# @author: Arvind Somya, Cisco Systems, Inc. (asomya@cisco.com) -# - -""" -PlugIn for Nexus OS driver -""" - -import logging - -from neutron.openstack.common import excutils -from neutron.openstack.common import importutils -from neutron.plugins.cisco.common import cisco_constants as const -from neutron.plugins.cisco.common import cisco_exceptions as cisco_exc -from neutron.plugins.cisco.common import config as conf -from neutron.plugins.cisco.db import network_db_v2 as cdb -from neutron.plugins.cisco.db import nexus_db_v2 as nxos_db -from neutron.plugins.cisco import l2device_plugin_base - - -LOG = logging.getLogger(__name__) - - -class NexusPlugin(l2device_plugin_base.L2DevicePluginBase): - """Nexus PlugIn Main Class.""" - _networks = {} - - def __init__(self): - """Extract configuration parameters from the configuration file.""" - self._client = importutils.import_object(conf.CISCO.nexus_driver) - LOG.debug(_("Loaded driver %s"), conf.CISCO.nexus_driver) - self._nexus_switches = conf.get_device_dictionary() - - def create_network(self, network, attachment): - """Create or update a network when an attachment is changed. - - This method is not invoked at the usual plugin create_network() time. - Instead, it is invoked on create/update port. - - :param network: Network on which the port operation is happening - :param attachment: Details about the owner of the port - - Create a VLAN in the appropriate switch/port, and configure the - appropriate interfaces for this VLAN. - """ - LOG.debug(_("NexusPlugin:create_network() called")) - # Grab the switch IPs and ports for this host - host_connections = [] - host = attachment['host_name'] - for switch_type, switch_ip, attr in self._nexus_switches: - if str(attr) == str(host): - port = self._nexus_switches[switch_type, switch_ip, attr] - # Get ether type for port, assume an ethernet type - # if none specified. - if ':' in port: - etype, port_id = port.split(':') - else: - etype, port_id = 'ethernet', port - host_connections.append((switch_ip, etype, port_id)) - if not host_connections: - raise cisco_exc.NexusComputeHostNotConfigured(host=host) - - vlan_id = network[const.NET_VLAN_ID] - vlan_name = network[const.NET_VLAN_NAME] - auto_create = True - auto_trunk = True - if cdb.is_provider_vlan(vlan_id): - vlan_name = ''.join([conf.CISCO.provider_vlan_name_prefix, - str(vlan_id)]) - auto_create = conf.CISCO.provider_vlan_auto_create - auto_trunk = conf.CISCO.provider_vlan_auto_trunk - - # Check if this network is already in the DB - for switch_ip, etype, port_id in host_connections: - vlan_created = False - vlan_trunked = False - eport_id = '%s:%s' % (etype, port_id) - # Check for switch vlan bindings - try: - # This vlan has already been created on this switch - # via another operation, like SVI bindings. - nxos_db.get_nexusvlan_binding(vlan_id, switch_ip) - vlan_created = True - auto_create = False - except cisco_exc.NexusPortBindingNotFound: - # No changes, proceed as normal - pass - - try: - nxos_db.get_port_vlan_switch_binding(eport_id, vlan_id, - switch_ip) - except cisco_exc.NexusPortBindingNotFound: - if auto_create and auto_trunk: - # Create vlan and trunk vlan on the port - LOG.debug(_("Nexus: create & trunk vlan %s"), vlan_name) - self._client.create_and_trunk_vlan( - switch_ip, vlan_id, vlan_name, etype, port_id) - vlan_created = True - vlan_trunked = True - elif auto_create: - # Create vlan but do not trunk it on the port - LOG.debug(_("Nexus: create vlan %s"), vlan_name) - self._client.create_vlan(switch_ip, vlan_id, vlan_name) - vlan_created = True - elif auto_trunk: - # Only trunk vlan on the port - LOG.debug(_("Nexus: trunk vlan %s"), vlan_name) - self._client.enable_vlan_on_trunk_int( - switch_ip, vlan_id, etype, port_id) - vlan_trunked = True - - try: - instance = attachment[const.INSTANCE_ID] - nxos_db.add_nexusport_binding(eport_id, str(vlan_id), - switch_ip, instance) - except Exception: - with excutils.save_and_reraise_exception(): - # Add binding failed, roll back any vlan creation/enabling - if vlan_created and vlan_trunked: - LOG.debug(_("Nexus: delete & untrunk vlan %s"), - vlan_name) - self._client.delete_and_untrunk_vlan(switch_ip, - vlan_id, - etype, port_id) - elif vlan_created: - LOG.debug(_("Nexus: delete vlan %s"), vlan_name) - self._client.delete_vlan(switch_ip, vlan_id) - elif vlan_trunked: - LOG.debug(_("Nexus: untrunk vlan %s"), vlan_name) - self._client.disable_vlan_on_trunk_int(switch_ip, - vlan_id, - etype, - port_id) - - net_id = network[const.NET_ID] - new_net_dict = {const.NET_ID: net_id, - const.NET_NAME: network[const.NET_NAME], - const.NET_PORTS: {}, - const.NET_VLAN_NAME: vlan_name, - const.NET_VLAN_ID: vlan_id} - self._networks[net_id] = new_net_dict - return new_net_dict - - def add_router_interface(self, vlan_name, vlan_id, subnet_id, - gateway_ip, router_id): - """Create VLAN SVI on the Nexus switch.""" - # Find a switch to create the SVI on - switch_ip = self._find_switch_for_svi() - if not switch_ip: - raise cisco_exc.NoNexusSviSwitch() - - # Check if this vlan exists on the switch already - try: - nxos_db.get_nexusvlan_binding(vlan_id, switch_ip) - except cisco_exc.NexusPortBindingNotFound: - # Create vlan and trunk vlan on the port - self._client.create_and_trunk_vlan( - switch_ip, vlan_id, vlan_name, etype=None, nexus_port=None) - # Check if a router interface has already been created - try: - nxos_db.get_nexusvm_bindings(vlan_id, router_id) - raise cisco_exc.SubnetInterfacePresent(subnet_id=subnet_id, - router_id=router_id) - except cisco_exc.NexusPortBindingNotFound: - self._client.create_vlan_svi(switch_ip, vlan_id, gateway_ip) - nxos_db.add_nexusport_binding('router', str(vlan_id), - switch_ip, router_id) - - return True - - def remove_router_interface(self, vlan_id, router_id): - """Remove VLAN SVI from the Nexus Switch.""" - # Grab switch_ip from database - switch_ip = nxos_db.get_nexusvm_bindings(vlan_id, - router_id)[0].switch_ip - - # Delete the SVI interface from the switch - self._client.delete_vlan_svi(switch_ip, vlan_id) - - # Invoke delete_port to delete this row - # And delete vlan if required - return self.delete_port(router_id, vlan_id) - - def _find_switch_for_svi(self): - """Get a switch to create the SVI on.""" - LOG.debug(_("Grabbing a switch to create SVI")) - nexus_switches = self._client.nexus_switches - if conf.CISCO.svi_round_robin: - LOG.debug(_("Using round robin to create SVI")) - switch_dict = dict( - (switch_ip, 0) for switch_ip, _ in nexus_switches) - try: - bindings = nxos_db.get_nexussvi_bindings() - # Build a switch dictionary with weights - for binding in bindings: - switch_ip = binding.switch_ip - if switch_ip not in switch_dict: - switch_dict[switch_ip] = 1 - else: - switch_dict[switch_ip] += 1 - # Search for the lowest value in the dict - if switch_dict: - switch_ip = min(switch_dict, key=switch_dict.get) - return switch_ip - except cisco_exc.NexusPortBindingNotFound: - pass - - LOG.debug(_("No round robin or zero weights, using first switch")) - # Return the first switch in the config - return conf.first_device_ip - - def delete_network(self, tenant_id, net_id, **kwargs): - """Delete network. - - Not applicable to Nexus plugin. Defined here to satisfy abstract - method requirements. - """ - LOG.debug(_("NexusPlugin:delete_network() called")) # pragma no cover - - def update_network(self, tenant_id, net_id, **kwargs): - """Update the properties of a particular Virtual Network. - - Not applicable to Nexus plugin. Defined here to satisfy abstract - method requirements. - """ - LOG.debug(_("NexusPlugin:update_network() called")) # pragma no cover - - def create_port(self, tenant_id, net_id, port_state, port_id, **kwargs): - """Create port. - - Not applicable to Nexus plugin. Defined here to satisfy abstract - method requirements. - """ - LOG.debug(_("NexusPlugin:create_port() called")) # pragma no cover - - def delete_port(self, device_id, vlan_id): - """Delete port. - - Delete port bindings from the database and scan whether the network - is still required on the interfaces trunked. - """ - LOG.debug(_("NexusPlugin:delete_port() called")) - # Delete DB row(s) for this port - try: - rows = nxos_db.get_nexusvm_bindings(vlan_id, device_id) - except cisco_exc.NexusPortBindingNotFound: - return - - auto_delete = True - auto_untrunk = True - if cdb.is_provider_vlan(vlan_id): - auto_delete = conf.CISCO.provider_vlan_auto_create - auto_untrunk = conf.CISCO.provider_vlan_auto_trunk - LOG.debug(_("delete_network(): provider vlan %s"), vlan_id) - - instance_id = False - for row in rows: - instance_id = row['instance_id'] - switch_ip = row.switch_ip - etype, nexus_port = '', '' - if row['port_id'] == 'router': - etype, nexus_port = 'vlan', row['port_id'] - auto_untrunk = False - else: - etype, nexus_port = row['port_id'].split(':') - - nxos_db.remove_nexusport_binding(row.port_id, row.vlan_id, - row.switch_ip, - row.instance_id) - # Check whether there are any remaining instances using this - # vlan on this Nexus port. - try: - nxos_db.get_port_vlan_switch_binding(row.port_id, - row.vlan_id, - row.switch_ip) - except cisco_exc.NexusPortBindingNotFound: - try: - if nexus_port and auto_untrunk: - # Untrunk the vlan from this Nexus interface - self._client.disable_vlan_on_trunk_int( - switch_ip, row.vlan_id, etype, nexus_port) - - # Check whether there are any remaining instances - # using this vlan on the Nexus switch. - if auto_delete: - try: - nxos_db.get_nexusvlan_binding(row.vlan_id, - row.switch_ip) - except cisco_exc.NexusPortBindingNotFound: - # Delete this vlan from this switch - self._client.delete_vlan(switch_ip, row.vlan_id) - except Exception: - # The delete vlan operation on the Nexus failed, - # so this delete_port request has failed. For - # consistency, roll back the Nexus database to what - # it was before this request. - with excutils.save_and_reraise_exception(): - nxos_db.add_nexusport_binding(row.port_id, - row.vlan_id, - row.switch_ip, - row.instance_id) - - return instance_id - - def update_port(self, tenant_id, net_id, port_id, port_state, **kwargs): - """Update port. - - Not applicable to Nexus plugin. Defined here to satisfy abstract - method requirements. - """ - LOG.debug(_("NexusPlugin:update_port() called")) # pragma no cover - - def plug_interface(self, tenant_id, net_id, port_id, remote_interface_id, - **kwargs): - """Plug interfaces. - - Not applicable to Nexus plugin. Defined here to satisfy abstract - method requirements. - """ - LOG.debug(_("NexusPlugin:plug_interface() called")) # pragma no cover - - def unplug_interface(self, tenant_id, net_id, port_id, **kwargs): - """Unplug interface. - - Not applicable to Nexus plugin. Defined here to satisfy abstract - method requirements. - """ - LOG.debug(_("NexusPlugin:unplug_interface() called") - ) # pragma no cover diff --git a/neutron/plugins/cisco/nexus/cisco_nexus_snippets.py b/neutron/plugins/cisco/nexus/cisco_nexus_snippets.py deleted file mode 100644 index 90d265443..000000000 --- a/neutron/plugins/cisco/nexus/cisco_nexus_snippets.py +++ /dev/null @@ -1,180 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2011 Cisco Systems, Inc. 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: Edgar Magana, Cisco Systems, Inc. -# @author: Arvind Somya (asomya@cisco.com) Cisco Systems, Inc. - -""" -Nexus-OS XML-based configuration snippets -""" - -import logging - - -LOG = logging.getLogger(__name__) - - -# The following are standard strings, messages used to communicate with Nexus, -EXEC_CONF_SNIPPET = """ - - - <__XML__MODE__exec_configure>%s - - - -""" - -CMD_VLAN_CONF_SNIPPET = """ - - - <__XML__PARAM_value>%s - <__XML__MODE_vlan> - - %s - - - - -""" - -CMD_VLAN_ACTIVE_SNIPPET = """ - - - <__XML__PARAM_value>%s - <__XML__MODE_vlan> - - active - - - - -""" - -CMD_VLAN_NO_SHUTDOWN_SNIPPET = """ - - - <__XML__PARAM_value>%s - <__XML__MODE_vlan> - - - - - - -""" - -CMD_NO_VLAN_CONF_SNIPPET = """ - - - - <__XML__PARAM_value>%s - - - -""" - -CMD_INT_VLAN_HEADER = """ - - <%s> - %s - <__XML__MODE_if-ethernet-switch> - - - - """ - -CMD_VLAN_ID = """ - %s""" - -CMD_VLAN_ADD_ID = """ - %s - """ % CMD_VLAN_ID - -CMD_INT_VLAN_TRAILER = """ - - - - - - - -""" - -CMD_INT_VLAN_SNIPPET = (CMD_INT_VLAN_HEADER + - CMD_VLAN_ID + - CMD_INT_VLAN_TRAILER) - -CMD_INT_VLAN_ADD_SNIPPET = (CMD_INT_VLAN_HEADER + - CMD_VLAN_ADD_ID + - CMD_INT_VLAN_TRAILER) - -CMD_NO_VLAN_INT_SNIPPET = """ - - <%s> - %s - <__XML__MODE_if-ethernet-switch> - - - - - - - %s - - - - - - - - -""" - -FILTER_SHOW_VLAN_BRIEF_SNIPPET = """ - - - - - -""" - -CMD_VLAN_SVI_SNIPPET = """ - - - %s - <__XML__MODE_vlan> - - - - -
-
%s
-
-
- -
-
-""" - -CMD_NO_VLAN_SVI_SNIPPET = """ - - - - %s - - - -""" diff --git a/neutron/plugins/cisco/test/__init__.py b/neutron/plugins/cisco/test/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/neutron/plugins/cisco/test/nexus/__init__.py b/neutron/plugins/cisco/test/nexus/__init__.py deleted file mode 100644 index a68ed41ea..000000000 --- a/neutron/plugins/cisco/test/nexus/__init__.py +++ /dev/null @@ -1,19 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012 OpenStack Foundation. -# 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. - -import __builtin__ -setattr(__builtin__, '_', lambda x: x) diff --git a/neutron/plugins/cisco/test/nexus/fake_nexus_driver.py b/neutron/plugins/cisco/test/nexus/fake_nexus_driver.py deleted file mode 100644 index b40cbef14..000000000 --- a/neutron/plugins/cisco/test/nexus/fake_nexus_driver.py +++ /dev/null @@ -1,101 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012 Cisco Systems, Inc. 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: Sumit Naiksatam, Cisco Systems, Inc. -# @author: Rohit Agarwalla, Cisco Systems, Inc. - - -class CiscoNEXUSFakeDriver(): - """Nexus Driver Fake Class.""" - - def __init__(self): - pass - - def nxos_connect(self, nexus_host, nexus_ssh_port, nexus_user, - nexus_password): - """Make the fake connection to the Nexus Switch.""" - pass - - def create_xml_snippet(self, cutomized_config): - """Create XML snippet. - - Creates the Proper XML structure for the Nexus Switch - Configuration. - """ - pass - - def enable_vlan(self, mgr, vlanid, vlanname): - """Create a VLAN on Nexus Switch given the VLAN ID and Name.""" - pass - - def disable_vlan(self, mgr, vlanid): - """Delete a VLAN on Nexus Switch given the VLAN ID.""" - pass - - def disable_switch_port(self, mgr, interface): - """Disable trunk mode an interface on Nexus Switch.""" - pass - - def enable_vlan_on_trunk_int(self, mgr, etype, interface, vlanid): - """Enable vlan on trunk interface. - - Enable trunk mode vlan access an interface on Nexus Switch given - VLANID. - """ - pass - - def disable_vlan_on_trunk_int(self, mgr, interface, vlanid): - """Disables vlan in trunk interface. - - Enables trunk mode vlan access an interface on Nexus Switch given - VLANID. - """ - pass - - def create_vlan(self, vlan_name, vlan_id, nexus_host, nexus_user, - nexus_password, nexus_ports, nexus_ssh_port, vlan_ids): - """Create VLAN and enable it on interface. - - Creates a VLAN and Enable on trunk mode an interface on Nexus Switch - given the VLAN ID and Name and Interface Number. - """ - pass - - def delete_vlan(self, vlan_id, nexus_host, nexus_user, nexus_password, - nexus_ports, nexus_ssh_port): - """Delete VLAN. - - Delete a VLAN and Disables trunk mode an interface on Nexus Switch - given the VLAN ID and Interface Number. - """ - pass - - def build_vlans_cmd(self): - """Build a string with all the VLANs on the same Switch.""" - pass - - def add_vlan_int(self, vlan_id, nexus_host, nexus_user, nexus_password, - nexus_ports, nexus_ssh_port, vlan_ids=None): - """Add a vlan from interfaces on the Nexus switch given the VLAN ID.""" - pass - - def remove_vlan_int(self, vlan_id, nexus_host, nexus_user, nexus_password, - nexus_ports, nexus_ssh_port): - """Remove vlan from interfaces. - - Removes a vlan from interfaces on the Nexus switch given the VLAN ID. - """ - pass diff --git a/neutron/plugins/embrane/README b/neutron/plugins/embrane/README deleted file mode 100644 index 15ad1abbd..000000000 --- a/neutron/plugins/embrane/README +++ /dev/null @@ -1,9 +0,0 @@ -Embrane Neutron Plugin - -This plugin interfaces OpenStack Neutron with Embrane's heleos platform, which -provides layer 3-7 network services for cloud environments. - -L2 connectivity is leveraged by one of the supported existing plugins. - -For more details on use, configuration and implementation please refer to: -http://wiki.openstack.org/wiki/Neutron/EmbraneNeutronPlugin \ No newline at end of file diff --git a/neutron/plugins/embrane/__init__.py b/neutron/plugins/embrane/__init__.py deleted file mode 100644 index 1fac4725b..000000000 --- a/neutron/plugins/embrane/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. diff --git a/neutron/plugins/embrane/agent/__init__.py b/neutron/plugins/embrane/agent/__init__.py deleted file mode 100644 index 1fac4725b..000000000 --- a/neutron/plugins/embrane/agent/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. diff --git a/neutron/plugins/embrane/agent/dispatcher.py b/neutron/plugins/embrane/agent/dispatcher.py deleted file mode 100644 index 121abe9ac..000000000 --- a/neutron/plugins/embrane/agent/dispatcher.py +++ /dev/null @@ -1,134 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - -from eventlet import greenthread -from eventlet import queue -from heleosapi import constants as h_con -from heleosapi import exceptions as h_exc - -from neutron.openstack.common import log as logging -from neutron.plugins.embrane.agent.operations import router_operations -from neutron.plugins.embrane.common import constants as p_con -from neutron.plugins.embrane.common import contexts as ctx - -LOG = logging.getLogger(__name__) - - -class Dispatcher(object): - - def __init__(self, plugin, async=True): - self._async = async - self._plugin = plugin - self.sync_items = dict() - - def dispatch_l3(self, d_context, args=(), kwargs={}): - item = d_context.item - event = d_context.event - n_context = d_context.n_context - chain = d_context.chain - - item_id = item["id"] - handlers = router_operations.handlers - if event in handlers: - for f in handlers[event]: - first_run = False - if item_id not in self.sync_items: - self.sync_items[item_id] = (queue.Queue(),) - first_run = True - self.sync_items[item_id][0].put( - ctx.OperationContext(event, n_context, item, chain, f, - args, kwargs)) - t = None - if first_run: - t = greenthread.spawn(self._consume_l3, - item_id, - self.sync_items[item_id][0], - self._plugin, - self._async) - self.sync_items[item_id] += (t,) - if not self._async: - t = self.sync_items[item_id][1] - t.wait() - - def _consume_l3(self, sync_item, sync_queue, plugin, a_sync): - current_state = None - while True: - try: - # If the DVA is deleted, the thread (and the associated queue) - # can die as well - if current_state == p_con.Status.DELETED: - del self.sync_items[sync_item] - return - try: - # If synchronous op, empty the queue as fast as possible - operation_context = sync_queue.get( - block=a_sync, - timeout=p_con.QUEUE_TIMEOUT) - except queue.Empty: - del self.sync_items[sync_item] - return - # Execute the preliminary operations - (operation_context.chain and - operation_context.chain.execute_all()) - # Execute the main operation, a transient state is maintained - # so that the consumer can decide if it has - # to be burned to the DB - transient_state = None - try: - dva_state = operation_context.function( - plugin._esm_api, - operation_context.n_context.tenant_id, - operation_context.item, - *operation_context.args, - **operation_context.kwargs) - if dva_state == p_con.Status.DELETED: - transient_state = dva_state - else: - if not dva_state: - transient_state = p_con.Status.ERROR - elif dva_state == h_con.DvaState.POWER_ON: - transient_state = p_con.Status.ACTIVE - else: - transient_state = p_con.Status.READY - - except (h_exc.PendingDva, h_exc.DvaNotFound, - h_exc.BrokenInterface, h_exc.DvaCreationFailed, - h_exc.DvaCreationPending, h_exc.BrokenDva, - h_exc.ConfigurationFailed) as ex: - LOG.warning(p_con.error_map[type(ex)] % ex.message) - transient_state = p_con.Status.ERROR - except h_exc.DvaDeleteFailed as ex: - LOG.warning(p_con.error_map[type(ex)] % ex.message) - transient_state = p_con.Status.DELETED - finally: - # if the returned transient state is None, no operations - # are required on the DVA status - if transient_state: - if transient_state == p_con.Status.DELETED: - current_state = plugin._delete_router( - operation_context.n_context, - operation_context.item["id"]) - # Error state cannot be reverted - elif transient_state != p_con.Status.ERROR: - current_state = plugin._update_neutron_state( - operation_context.n_context, - operation_context.item, - transient_state) - except Exception: - LOG.exception(_("Unhandled exception occurred")) diff --git a/neutron/plugins/embrane/agent/operations/__init__.py b/neutron/plugins/embrane/agent/operations/__init__.py deleted file mode 100644 index 1fac4725b..000000000 --- a/neutron/plugins/embrane/agent/operations/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. diff --git a/neutron/plugins/embrane/agent/operations/router_operations.py b/neutron/plugins/embrane/agent/operations/router_operations.py deleted file mode 100644 index a9d35bfd4..000000000 --- a/neutron/plugins/embrane/agent/operations/router_operations.py +++ /dev/null @@ -1,156 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - -import functools - -from heleosapi import exceptions as h_exc - -from neutron.openstack.common import log as logging -from neutron.plugins.embrane.common import constants as p_con - -LOG = logging.getLogger(__name__) -handlers = dict() - - -def handler(event, handler): - def wrap(f): - if event not in handler.keys(): - new_func_list = [f] - handler[event] = new_func_list - else: - handler[event].append(f) - - @functools.wraps(f) - def wrapped_f(*args, **kwargs): - return f(*args, **kwargs) - return wrapped_f - return wrap - - -@handler(p_con.Events.CREATE_ROUTER, handlers) -def _create_dva_and_assign_address(api, tenant_id, neutron_router, - flavor, utif_info=None, - ip_allocation_info=None): - """Creates a new router, and assign the gateway interface if any.""" - - dva = api.create_router(tenant_id=tenant_id, - router_id=neutron_router["id"], - name=neutron_router["name"], - flavor=flavor, - up=neutron_router["admin_state_up"]) - try: - if utif_info: - api.grow_interface(utif_info, neutron_router["admin_state_up"], - tenant_id, neutron_router["id"]) - if ip_allocation_info: - dva = api.allocate_address(neutron_router["id"], - neutron_router["admin_state_up"], - ip_allocation_info) - except h_exc.PreliminaryOperationsFailed as ex: - raise h_exc.BrokenInterface(err_msg=ex.message) - - state = api.extract_dva_state(dva) - return state - - -@handler(p_con.Events.UPDATE_ROUTER, handlers) -def _update_dva_and_assign_address(api, tenant_id, neutron_router, - utif_info=None, ip_allocation_info=None, - routes_info=[]): - name = neutron_router["name"] - up = neutron_router["admin_state_up"] - r_id = neutron_router["id"] - if ip_allocation_info or routes_info: - up = True - dva = api.update_dva(tenant_id=tenant_id, router_id=r_id, name=name, - up=up, utif_info=utif_info) - if ip_allocation_info: - api.allocate_address(r_id, up, ip_allocation_info) - - if routes_info: - api.delete_extra_routes(r_id, up) - api.set_extra_routes(r_id, neutron_router["admin_state_up"], - routes_info) - - return api.extract_dva_state(dva) - - -@handler(p_con.Events.DELETE_ROUTER, handlers) -def _delete_dva(api, tenant_id, neutron_router): - try: - api.delete_dva(tenant_id, neutron_router["id"]) - except h_exc.DvaNotFound: - LOG.warning(_("The router %s had no physical representation," - "likely already deleted"), neutron_router["id"]) - return p_con.Status.DELETED - - -@handler(p_con.Events.GROW_ROUTER_IF, handlers) -def _grow_dva_iface_and_assign_address(api, tenant_id, neutron_router, - utif_info=None, - ip_allocation_info=None): - try: - dva = api.grow_interface(utif_info, neutron_router["admin_state_up"], - tenant_id, neutron_router["id"]) - if ip_allocation_info: - dva = api.allocate_address(neutron_router["id"], - neutron_router["admin_state_up"], - ip_allocation_info) - except h_exc.PreliminaryOperationsFailed as ex: - raise h_exc.BrokenInterface(err_msg=ex.message) - - state = api.extract_dva_state(dva) - return state - - -@handler(p_con.Events.SHRINK_ROUTER_IF, handlers) -def _shrink_dva_iface(api, tenant_id, neutron_router, port_id): - try: - dva = api.shrink_interface(tenant_id, neutron_router["id"], - neutron_router["admin_state_up"], port_id) - except h_exc.InterfaceNotFound: - LOG.warning(_("Interface %s not found in the heleos back-end," - "likely already deleted"), port_id) - return (p_con.Status.ACTIVE if neutron_router["admin_state_up"] else - p_con.Status.READY) - except h_exc.PreliminaryOperationsFailed as ex: - raise h_exc.BrokenInterface(err_msg=ex.message) - state = api.extract_dva_state(dva) - return state - - -@handler(p_con.Events.SET_NAT_RULE, handlers) -def _create_nat_rule(api, tenant_id, neutron_router, nat_info=None): - - dva = api.create_nat_entry(neutron_router["id"], - neutron_router["admin_state_up"], nat_info) - - state = api.extract_dva_state(dva) - return state - - -@handler(p_con.Events.RESET_NAT_RULE, handlers) -def _delete_nat_rule(api, tenant_id, neutron_router, floating_ip_id): - - dva = api.remove_nat_entry(neutron_router["id"], - neutron_router["admin_state_up"], - floating_ip_id) - - state = api.extract_dva_state(dva) - return state diff --git a/neutron/plugins/embrane/base_plugin.py b/neutron/plugins/embrane/base_plugin.py deleted file mode 100644 index 33d213888..000000000 --- a/neutron/plugins/embrane/base_plugin.py +++ /dev/null @@ -1,375 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - -from heleosapi import backend_operations as h_op -from heleosapi import constants as h_con -from heleosapi import exceptions as h_exc -from oslo.config import cfg -from sqlalchemy.orm import exc - -from neutron.common import constants as l3_constants -from neutron.common import exceptions as neutron_exc -from neutron.db import extraroute_db -from neutron.db import l3_db -from neutron.db import models_v2 -from neutron.extensions import l3 -from neutron.openstack.common import log as logging -from neutron.plugins.embrane.agent import dispatcher -from neutron.plugins.embrane.common import config # noqa -from neutron.plugins.embrane.common import constants as p_con -from neutron.plugins.embrane.common import contexts as embrane_ctx -from neutron.plugins.embrane.common import operation -from neutron.plugins.embrane.common import utils - -LOG = logging.getLogger(__name__) -conf = cfg.CONF.heleos - - -class EmbranePlugin(object): - """Embrane Neutron plugin. - - uses the heleos(c) platform and a support L2 plugin to leverage networking - in cloud environments. - - """ - _l3super = extraroute_db.ExtraRoute_db_mixin - - def __init__(self): - pass - - def _run_embrane_config(self): - # read configurations - config_esm_mgmt = conf.esm_mgmt - config_admin_username = conf.admin_username - config_admin_password = conf.admin_password - config_router_image_id = conf.router_image - config_security_zones = {h_con.SzType.IB: conf.inband_id, - h_con.SzType.OOB: conf.oob_id, - h_con.SzType.MGMT: conf.mgmt_id, - h_con.SzType.DUMMY: conf.dummy_utif_id} - config_resource_pool = conf.resource_pool_id - self._embrane_async = conf.async_requests - self._esm_api = h_op.BackendOperations( - esm_mgmt=config_esm_mgmt, - admin_username=config_admin_username, - admin_password=config_admin_password, - router_image_id=config_router_image_id, - security_zones=config_security_zones, - resource_pool=config_resource_pool) - self._dispatcher = dispatcher.Dispatcher(self, self._embrane_async) - - def _make_router_dict(self, *args, **kwargs): - return self._l3super._make_router_dict(self, *args, **kwargs) - - def _delete_router(self, context, router_id): - self._l3super.delete_router(self, context, router_id) - - def _update_db_router_state(self, context, neutron_router, dva_state): - if not dva_state: - new_state = p_con.Status.ERROR - elif dva_state == h_con.DvaState.POWER_ON: - new_state = p_con.Status.ACTIVE - else: - new_state = p_con.Status.READY - self._set_db_router_state(context, neutron_router, new_state) - return new_state - - def _set_db_router_state(self, context, neutron_router, new_state): - return utils.set_db_item_state(context, neutron_router, new_state) - - def _update_db_interfaces_state(self, context, neutron_router): - router_ports = self.get_ports(context, - {"device_id": [neutron_router["id"]]}) - self._esm_api.update_ports_status(neutron_router["id"], router_ports) - for port in router_ports: - db_port = self._get_port(context, port["id"]) - db_port["status"] = port["status"] - context.session.merge(db_port) - - def _update_neutron_state(self, context, neutron_router, state): - try: - self._update_db_interfaces_state(context, neutron_router) - except Exception: - LOG.exception(_("Unhandled exception occurred")) - return self._set_db_router_state(context, neutron_router, state) - - def _retrieve_prefix_from_port(self, context, neutron_port): - subnet_id = neutron_port["fixed_ips"][0]["subnet_id"] - subnet = utils.retrieve_subnet(context, subnet_id) - prefix = subnet["cidr"].split("/")[1] - return prefix - - # L3 extension - def create_router(self, context, router): - r = router["router"] - self._get_tenant_id_for_create(context, r) - db_router = self._l3super.create_router(self, context, router) - neutron_router = self._get_router(context, db_router['id']) - gw_port = neutron_router.gw_port - # For now, only small flavor is used - utif_info = (self._plugin_support.retrieve_utif_info(context, - gw_port) - if gw_port else None) - ip_allocation_info = (utils.retrieve_ip_allocation_info(context, - gw_port) - if gw_port else None) - neutron_router = self._l3super._get_router(self, context, - neutron_router["id"]) - neutron_router["status"] = p_con.Status.CREATING - self._dispatcher.dispatch_l3( - d_context=embrane_ctx.DispatcherContext( - p_con.Events.CREATE_ROUTER, neutron_router, context, None), - args=(h_con.Flavor.SMALL, utif_info, ip_allocation_info)) - return self._make_router_dict(neutron_router) - - def update_router(self, context, id, router): - db_router = self._l3super.update_router(self, context, id, router) - neutron_router = self._get_router(context, db_router['id']) - gw_port = neutron_router.gw_port - utif_info = (self._plugin_support.retrieve_utif_info(context, - gw_port) - if gw_port else None) - ip_allocation_info = (utils.retrieve_ip_allocation_info(context, - gw_port) - if gw_port else None) - - routes_info = router["router"].get("routes") - - neutron_router = self._l3super._get_router(self, context, id) - state_change = operation.Operation( - self._set_db_router_state, - args=(context, neutron_router, p_con.Status.UPDATING)) - self._dispatcher.dispatch_l3( - d_context=embrane_ctx.DispatcherContext( - p_con.Events.UPDATE_ROUTER, neutron_router, context, - state_change), - args=(utif_info, ip_allocation_info, routes_info)) - return self._make_router_dict(neutron_router) - - def get_router(self, context, id, fields=None): - """Ensures that id does exist in the ESM.""" - neutron_router = self._get_router(context, id) - - try: - if neutron_router["status"] != p_con.Status.CREATING: - self._esm_api.get_dva(id) - except h_exc.DvaNotFound: - - LOG.error(_("The following routers have not physical match: %s"), - id) - self._set_db_router_state(context, neutron_router, - p_con.Status.ERROR) - - LOG.debug(_("Requested router: %s"), neutron_router) - return self._make_router_dict(neutron_router, fields) - - def get_routers(self, context, filters=None, fields=None, sorts=None, - limit=None, marker=None, page_reverse=False): - """Retrieves the router list defined by the incoming filters.""" - router_query = self._apply_filters_to_query( - self._model_query(context, l3_db.Router), - l3_db.Router, filters) - id_list = [x["id"] for x in router_query - if x["status"] != p_con.Status.CREATING] - try: - self._esm_api.get_dvas(id_list) - except h_exc.DvaNotFound: - LOG.error(_("The following routers have not physical match: %s"), - repr(id_list)) - error_routers = [] - for id in id_list: - try: - error_routers.append(self._get_router(context, id)) - except l3.RouterNotFound: - pass - for error_router in error_routers: - self._set_db_router_state(context, error_router, - p_con.Status.ERROR) - return [self._make_router_dict(router, fields) - for router in router_query] - - def delete_router(self, context, id): - """Deletes the DVA with the specific router id.""" - # Copy of the parent validation code, shouldn't the base modules - # provide functions for validating operations? - device_owner_router_intf = l3_constants.DEVICE_OWNER_ROUTER_INTF - fips = self.get_floatingips_count(context.elevated(), - filters={"router_id": [id]}) - if fips: - raise l3.RouterInUse(router_id=id) - - device_filter = {"device_id": [id], - "device_owner": [device_owner_router_intf]} - ports = self.get_ports_count(context.elevated(), - filters=device_filter) - if ports: - raise l3.RouterInUse(router_id=id) - neutron_router = self._get_router(context, id) - state_change = operation.Operation(self._set_db_router_state, - args=(context, neutron_router, - p_con.Status.DELETING)) - self._dispatcher.dispatch_l3( - d_context=embrane_ctx.DispatcherContext( - p_con.Events.DELETE_ROUTER, neutron_router, context, - state_change), args=()) - LOG.debug(_("Deleting router=%s"), neutron_router) - return neutron_router - - def add_router_interface(self, context, router_id, interface_info): - """Grows DVA interface in the specified subnet.""" - neutron_router = self._get_router(context, router_id) - rport_qry = context.session.query(models_v2.Port) - ports = rport_qry.filter_by( - device_id=router_id).all() - if len(ports) >= p_con.UTIF_LIMIT: - raise neutron_exc.BadRequest( - resource=router_id, - msg=("this router doesn't support more than " - + str(p_con.UTIF_LIMIT) + " interfaces")) - neutron_router_iface = self._l3super.add_router_interface( - self, context, router_id, interface_info) - port = self._get_port(context, neutron_router_iface["port_id"]) - utif_info = self._plugin_support.retrieve_utif_info(context, port) - ip_allocation_info = utils.retrieve_ip_allocation_info(context, - port) - state_change = operation.Operation(self._set_db_router_state, - args=(context, neutron_router, - p_con.Status.UPDATING)) - self._dispatcher.dispatch_l3( - d_context=embrane_ctx.DispatcherContext( - p_con.Events.GROW_ROUTER_IF, neutron_router, context, - state_change), - args=(utif_info, ip_allocation_info)) - return neutron_router_iface - - def remove_router_interface(self, context, router_id, interface_info): - port_id = None - if "port_id" in interface_info: - port_id = interface_info["port_id"] - elif "subnet_id" in interface_info: - subnet_id = interface_info["subnet_id"] - subnet = utils.retrieve_subnet(context, subnet_id) - rport_qry = context.session.query(models_v2.Port) - ports = rport_qry.filter_by( - device_id=router_id, - device_owner=l3_constants.DEVICE_OWNER_ROUTER_INTF, - network_id=subnet["network_id"]) - for p in ports: - if p["fixed_ips"][0]["subnet_id"] == subnet_id: - port_id = p["id"] - break - neutron_router = self._get_router(context, router_id) - self._l3super.remove_router_interface(self, context, router_id, - interface_info) - state_change = operation.Operation(self._set_db_router_state, - args=(context, neutron_router, - p_con.Status.UPDATING)) - self._dispatcher.dispatch_l3( - d_context=embrane_ctx.DispatcherContext( - p_con.Events.SHRINK_ROUTER_IF, neutron_router, context, - state_change), - args=(port_id,)) - - def create_floatingip(self, context, floatingip): - result = self._l3super.create_floatingip( - self, context, floatingip) - - if result["port_id"]: - neutron_router = self._get_router(context, result["router_id"]) - db_fixed_port = self._get_port(context, result["port_id"]) - fixed_prefix = self._retrieve_prefix_from_port(context, - db_fixed_port) - db_floating_port = neutron_router["gw_port"] - floating_prefix = self._retrieve_prefix_from_port( - context, db_floating_port) - nat_info = utils.retrieve_nat_info(context, result, - fixed_prefix, - floating_prefix, - neutron_router) - state_change = operation.Operation( - self._set_db_router_state, - args=(context, neutron_router, p_con.Status.UPDATING)) - - self._dispatcher.dispatch_l3( - d_context=embrane_ctx.DispatcherContext( - p_con.Events.SET_NAT_RULE, neutron_router, context, - state_change), - args=(nat_info,)) - return result - - def update_floatingip(self, context, id, floatingip): - db_fip = self._l3super.get_floatingip(self, context, id) - result = self._l3super.update_floatingip(self, context, id, - floatingip) - - if db_fip["port_id"] and db_fip["port_id"] != result["port_id"]: - neutron_router = self._get_router(context, db_fip["router_id"]) - fip_id = db_fip["id"] - state_change = operation.Operation( - self._set_db_router_state, - args=(context, neutron_router, p_con.Status.UPDATING)) - - self._dispatcher.dispatch_l3( - d_context=embrane_ctx.DispatcherContext( - p_con.Events.RESET_NAT_RULE, neutron_router, context, - state_change), - args=(fip_id,)) - if result["port_id"]: - neutron_router = self._get_router(context, result["router_id"]) - db_fixed_port = self._get_port(context, result["port_id"]) - fixed_prefix = self._retrieve_prefix_from_port(context, - db_fixed_port) - db_floating_port = neutron_router["gw_port"] - floating_prefix = self._retrieve_prefix_from_port( - context, db_floating_port) - nat_info = utils.retrieve_nat_info(context, result, - fixed_prefix, - floating_prefix, - neutron_router) - state_change = operation.Operation( - self._set_db_router_state, - args=(context, neutron_router, p_con.Status.UPDATING)) - - self._dispatcher.dispatch_l3( - d_context=embrane_ctx.DispatcherContext( - p_con.Events.SET_NAT_RULE, neutron_router, context, - state_change), - args=(nat_info,)) - return result - - def disassociate_floatingips(self, context, port_id): - try: - fip_qry = context.session.query(l3_db.FloatingIP) - floating_ip = fip_qry.filter_by(fixed_port_id=port_id).one() - router_id = floating_ip["router_id"] - except exc.NoResultFound: - return - self._l3super.disassociate_floatingips(self, context, port_id) - if router_id: - neutron_router = self._get_router(context, router_id) - fip_id = floating_ip["id"] - state_change = operation.Operation( - self._set_db_router_state, - args=(context, neutron_router, p_con.Status.UPDATING)) - - self._dispatcher.dispatch_l3( - d_context=embrane_ctx.DispatcherContext( - p_con.Events.RESET_NAT_RULE, neutron_router, context, - state_change), - args=(fip_id,)) diff --git a/neutron/plugins/embrane/common/__init__.py b/neutron/plugins/embrane/common/__init__.py deleted file mode 100644 index 1fac4725b..000000000 --- a/neutron/plugins/embrane/common/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. diff --git a/neutron/plugins/embrane/common/config.py b/neutron/plugins/embrane/common/config.py deleted file mode 100644 index 54c9153f3..000000000 --- a/neutron/plugins/embrane/common/config.py +++ /dev/null @@ -1,49 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - -from oslo.config import cfg - - -heleos_opts = [ - cfg.StrOpt('esm_mgmt', - help=_('ESM management root address')), - cfg.StrOpt('admin_username', default='admin', - help=_('ESM admin username.')), - cfg.StrOpt('admin_password', - secret=True, - help=_('ESM admin password.')), - cfg.StrOpt('router_image', - help=_('Router image id (Embrane FW/VPN)')), - cfg.StrOpt('inband_id', - help=_('In band Security Zone id')), - cfg.StrOpt('oob_id', - help=_('Out of band Security Zone id')), - cfg.StrOpt('mgmt_id', - help=_('Management Security Zone id')), - cfg.StrOpt('dummy_utif_id', - help=_('Dummy user traffic Security Zone id')), - cfg.StrOpt('resource_pool_id', default='default', - help=_('Shared resource pool id')), - cfg.BoolOpt('async_requests', default=True, - help=_('Define if the requests have ' - 'run asynchronously or not')), -] - - -cfg.CONF.register_opts(heleos_opts, "heleos") diff --git a/neutron/plugins/embrane/common/constants.py b/neutron/plugins/embrane/common/constants.py deleted file mode 100644 index 65f3818a2..000000000 --- a/neutron/plugins/embrane/common/constants.py +++ /dev/null @@ -1,72 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - -from heleosapi import exceptions as h_exc - -from neutron.plugins.common import constants - - -# Router specific constants -UTIF_LIMIT = 7 -QUEUE_TIMEOUT = 300 - - -class Status: - # Transient - CREATING = constants.PENDING_CREATE - UPDATING = constants.PENDING_UPDATE - DELETING = constants.PENDING_DELETE - # Final - ACTIVE = constants.ACTIVE - ERROR = constants.ERROR - READY = constants.INACTIVE - DELETED = "DELETED" # not visible - - -class Events: - CREATE_ROUTER = "create_router" - UPDATE_ROUTER = "update_router" - DELETE_ROUTER = "delete_router" - GROW_ROUTER_IF = "grow_router_if" - SHRINK_ROUTER_IF = "shrink_router_if" - SET_NAT_RULE = "set_nat_rule" - RESET_NAT_RULE = "reset_nat_rule" - -_DVA_PENDING_ERROR_MSG = _("Dva is pending for the following reason: %s") -_DVA_NOT_FOUNT_ERROR_MSG = _("Dva can't be found to execute the operation, " - "probably was cancelled through the heleos UI") -_DVA_BROKEN_ERROR_MSG = _("Dva seems to be broken for reason %s") -_DVA_BROKEN_INTERFACE_ERROR_MSG = _("Dva interface seems to be broken " - "for reason %s") -_DVA_CREATION_FAILED_ERROR_MSG = _("Dva creation failed reason %s") -_DVA_CREATION_PENDING_ERROR_MSG = _("Dva creation is in pending state " - "for reason %s") -_CFG_FAILED_ERROR_MSG = _("Dva configuration failed for reason %s") -_DVA_DEL_FAILED_ERROR_MSG = _("Failed to delete the backend " - "router for reason %s. Please remove " - "it manually through the heleos UI") - -error_map = {h_exc.PendingDva: _DVA_PENDING_ERROR_MSG, - h_exc.DvaNotFound: _DVA_NOT_FOUNT_ERROR_MSG, - h_exc.BrokenDva: _DVA_BROKEN_ERROR_MSG, - h_exc.BrokenInterface: _DVA_BROKEN_INTERFACE_ERROR_MSG, - h_exc.DvaCreationFailed: _DVA_CREATION_FAILED_ERROR_MSG, - h_exc.DvaCreationPending: _DVA_CREATION_PENDING_ERROR_MSG, - h_exc.ConfigurationFailed: _CFG_FAILED_ERROR_MSG, - h_exc.DvaDeleteFailed: _DVA_DEL_FAILED_ERROR_MSG} diff --git a/neutron/plugins/embrane/common/contexts.py b/neutron/plugins/embrane/common/contexts.py deleted file mode 100644 index f35a02427..000000000 --- a/neutron/plugins/embrane/common/contexts.py +++ /dev/null @@ -1,40 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - - -class DispatcherContext(object): - - def __init__(self, event, item, neutron_context, chain=None): - self.event = event - self.item = item - self.n_context = neutron_context - self.chain = chain - - -class OperationContext(DispatcherContext): - """Operational context. - - contains all the parameters needed to execute a status aware operation - - """ - def __init__(self, event, context, item, chain, function, args, kwargs): - super(OperationContext, self).__init__(event, item, context, chain) - self.function = function - self.args = args - self.kwargs = kwargs diff --git a/neutron/plugins/embrane/common/exceptions.py b/neutron/plugins/embrane/common/exceptions.py deleted file mode 100644 index f7cfa7b24..000000000 --- a/neutron/plugins/embrane/common/exceptions.py +++ /dev/null @@ -1,28 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - -from neutron.common import exceptions as neutron_exec - - -class EmbranePluginException(neutron_exec.NeutronException): - message = _("An unexpected error occurred:%(err_msg)s") - - -class UnsupportedException(EmbranePluginException): - message = _("%(err_msg)s") diff --git a/neutron/plugins/embrane/common/operation.py b/neutron/plugins/embrane/common/operation.py deleted file mode 100644 index 39fa413e2..000000000 --- a/neutron/plugins/embrane/common/operation.py +++ /dev/null @@ -1,51 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - - -class Operation(object): - """Defines a series of operations which shall be executed in order. - - the operations expected are procedures, return values are discarded - - """ - - def __init__(self, procedure, args=(), kwargs={}, nextop=None): - self._procedure = procedure - self.args = args[:] - self.kwargs = dict(kwargs) - self.nextop = nextop - - def execute(self): - args = self.args - self._procedure(*args, **self.kwargs) - return self.nextop - - def execute_all(self): - nextop = self.execute() - while nextop: - nextop = self.execute_all() - - def has_next(self): - return self.nextop is not None - - def add_bottom_operation(self, operation): - op = self - while op.has_next(): - op = op.nextop - op.nextop = operation diff --git a/neutron/plugins/embrane/common/utils.py b/neutron/plugins/embrane/common/utils.py deleted file mode 100644 index 5fa20eb59..000000000 --- a/neutron/plugins/embrane/common/utils.py +++ /dev/null @@ -1,73 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - -from heleosapi import info as h_info - -from neutron.common import constants -from neutron.db import models_v2 -from neutron.openstack.common import log as logging - -LOG = logging.getLogger(__name__) - - -def set_db_item_state(context, neutron_item, new_state): - with context.session.begin(subtransactions=True): - if neutron_item["status"] != new_state: - neutron_item["status"] = new_state - context.session.merge(neutron_item) - - -def retrieve_subnet(context, subnet_id): - return (context.session.query( - models_v2.Subnet).filter(models_v2.Subnet.id == subnet_id).one()) - - -def retrieve_ip_allocation_info(context, neutron_port): - """Retrieves ip allocation info for a specific port if any.""" - - try: - subnet_id = neutron_port["fixed_ips"][0]["subnet_id"] - except (KeyError, IndexError): - LOG.info(_("No ip allocation set")) - return - subnet = retrieve_subnet(context, subnet_id) - allocated_ip = neutron_port["fixed_ips"][0]["ip_address"] - is_gw_port = (neutron_port["device_owner"] == - constants.DEVICE_OWNER_ROUTER_GW) - gateway_ip = subnet["gateway_ip"] - - ip_allocation_info = h_info.IpAllocationInfo( - is_gw=is_gw_port, - ip_version=subnet["ip_version"], - prefix=subnet["cidr"].split("/")[1], - ip_address=allocated_ip, - port_id=neutron_port["id"], - gateway_ip=gateway_ip) - - return ip_allocation_info - - -def retrieve_nat_info(context, fip, fixed_prefix, floating_prefix, router): - nat_info = h_info.NatInfo(source_address=fip["floating_ip_address"], - source_prefix=floating_prefix, - destination_address=fip["fixed_ip_address"], - destination_prefix=fixed_prefix, - floating_ip_id=fip["id"], - fixed_port_id=fip["port_id"]) - return nat_info diff --git a/neutron/plugins/embrane/l2base/__init__.py b/neutron/plugins/embrane/l2base/__init__.py deleted file mode 100644 index 1fac4725b..000000000 --- a/neutron/plugins/embrane/l2base/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. diff --git a/neutron/plugins/embrane/l2base/fake/__init__.py b/neutron/plugins/embrane/l2base/fake/__init__.py deleted file mode 100644 index 1fac4725b..000000000 --- a/neutron/plugins/embrane/l2base/fake/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. diff --git a/neutron/plugins/embrane/l2base/fake/fake_l2_plugin.py b/neutron/plugins/embrane/l2base/fake/fake_l2_plugin.py deleted file mode 100644 index 5cf68df28..000000000 --- a/neutron/plugins/embrane/l2base/fake/fake_l2_plugin.py +++ /dev/null @@ -1,24 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - -from neutron.db import db_base_plugin_v2 - - -class FakeL2Plugin(db_base_plugin_v2.NeutronDbPluginV2): - supported_extension_aliases = [] diff --git a/neutron/plugins/embrane/l2base/fake/fakeplugin_support.py b/neutron/plugins/embrane/l2base/fake/fakeplugin_support.py deleted file mode 100644 index 7818d28de..000000000 --- a/neutron/plugins/embrane/l2base/fake/fakeplugin_support.py +++ /dev/null @@ -1,45 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - -from heleosapi import info as h_info - -from neutron.common import constants -from neutron import manager -from neutron.plugins.embrane.l2base import support_base as base - - -class FakePluginSupport(base.SupportBase): - - def __init__(self): - super(FakePluginSupport, self).__init__() - - def retrieve_utif_info(self, context, neutron_port): - plugin = manager.NeutronManager.get_plugin() - network_id = neutron_port["network_id"] - network = plugin._get_network(context, network_id) - is_gw = (neutron_port["device_owner"] == - constants.DEVICE_OWNER_ROUTER_GW) - result = h_info.UtifInfo(vlan=0, - network_name=network["name"], - network_id=network["id"], - is_gw=is_gw, - owner_tenant=network["tenant_id"], - port_id=neutron_port["id"], - mac_address=neutron_port["mac_address"]) - return result diff --git a/neutron/plugins/embrane/l2base/openvswitch/__init__.py b/neutron/plugins/embrane/l2base/openvswitch/__init__.py deleted file mode 100644 index 1fac4725b..000000000 --- a/neutron/plugins/embrane/l2base/openvswitch/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. diff --git a/neutron/plugins/embrane/l2base/openvswitch/openvswitch_support.py b/neutron/plugins/embrane/l2base/openvswitch/openvswitch_support.py deleted file mode 100644 index f37a6b81a..000000000 --- a/neutron/plugins/embrane/l2base/openvswitch/openvswitch_support.py +++ /dev/null @@ -1,58 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - -from heleosapi import info as h_info - -from neutron.common import constants -from neutron import manager -from neutron.plugins.embrane.l2base import support_base as base -from neutron.plugins.embrane.l2base import support_exceptions as exc -from neutron.plugins.openvswitch import ovs_db_v2 - - -class OpenvswitchSupport(base.SupportBase): - """OpenVSwitch plugin support. - - Obtains the informations needed to build the user security zones - - """ - - def __init__(self): - super(OpenvswitchSupport, self).__init__() - - def retrieve_utif_info(self, context, neutron_port): - plugin = manager.NeutronManager.get_plugin() - session = context.session - network_id = neutron_port["network_id"] - network_binding = ovs_db_v2.get_network_binding(session, network_id) - if not network_binding["segmentation_id"]: - raise exc.UtifInfoError( - err_msg=_("No segmentation_id found for the network, " - "please be sure that tenant_network_type is vlan")) - network = plugin._get_network(context, network_id) - is_gw = (neutron_port["device_owner"] == - constants.DEVICE_OWNER_ROUTER_GW) - result = h_info.UtifInfo(vlan=network_binding["segmentation_id"], - network_name=network["name"], - network_id=network["id"], - is_gw=is_gw, - owner_tenant=network["tenant_id"], - port_id=neutron_port["id"], - mac_address=neutron_port["mac_address"]) - return result diff --git a/neutron/plugins/embrane/l2base/support_base.py b/neutron/plugins/embrane/l2base/support_base.py deleted file mode 100644 index a2b7e5342..000000000 --- a/neutron/plugins/embrane/l2base/support_base.py +++ /dev/null @@ -1,50 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - -import abc - -import six - - -@six.add_metaclass(abc.ABCMeta) -class SupportBase(object): - """abstract support class. - - Defines the methods a plugin support should implement to be used as - the L2 base for Embrane plugin. - - """ - - @abc.abstractmethod - def __init__(self): - pass - - @abc.abstractmethod - def retrieve_utif_info(self, context, neutron_port=None, network=None): - """Retrieve specific network info. - - each plugin support, querying its own DB, can collect all the - information needed by the ESM in order to create the - user traffic security zone. - - :param interface_info: the foo parameter - :param context: neutron request context - :returns: heleosapi.info.UtifInfo -- specific network info - :raises: UtifInfoError - """ diff --git a/neutron/plugins/embrane/l2base/support_exceptions.py b/neutron/plugins/embrane/l2base/support_exceptions.py deleted file mode 100644 index 1c5c01322..000000000 --- a/neutron/plugins/embrane/l2base/support_exceptions.py +++ /dev/null @@ -1,25 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - -from neutron.plugins.embrane.common import exceptions as embrane_exc - - -class UtifInfoError(embrane_exc.EmbranePluginException): - message = _("Cannot retrieve utif info for the following reason: " - "%(err_msg)s") diff --git a/neutron/plugins/embrane/plugins/__init__.py b/neutron/plugins/embrane/plugins/__init__.py deleted file mode 100644 index 1fac4725b..000000000 --- a/neutron/plugins/embrane/plugins/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. diff --git a/neutron/plugins/embrane/plugins/embrane_fake_plugin.py b/neutron/plugins/embrane/plugins/embrane_fake_plugin.py deleted file mode 100644 index 69d972c54..000000000 --- a/neutron/plugins/embrane/plugins/embrane_fake_plugin.py +++ /dev/null @@ -1,34 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - -from neutron.db import extraroute_db -from neutron.plugins.embrane import base_plugin as base -from neutron.plugins.embrane.l2base.fake import fake_l2_plugin as l2 -from neutron.plugins.embrane.l2base.fake import fakeplugin_support as sup - - -class EmbraneFakePlugin(base.EmbranePlugin, extraroute_db.ExtraRoute_db_mixin, - l2.FakeL2Plugin): - _plugin_support = sup.FakePluginSupport() - - def __init__(self): - '''First run plugin specific initialization, then Embrane's.''' - self.supported_extension_aliases += ["extraroute", "router"] - l2.FakeL2Plugin.__init__(self) - self._run_embrane_config() diff --git a/neutron/plugins/embrane/plugins/embrane_ovs_plugin.py b/neutron/plugins/embrane/plugins/embrane_ovs_plugin.py deleted file mode 100644 index d4d5ac180..000000000 --- a/neutron/plugins/embrane/plugins/embrane_ovs_plugin.py +++ /dev/null @@ -1,38 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Embrane, Inc. -# 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: Ivar Lazzaro, Embrane, Inc. - -from neutron.plugins.embrane import base_plugin as base -from neutron.plugins.embrane.l2base.openvswitch import openvswitch_support -from neutron.plugins.openvswitch import ovs_neutron_plugin as l2 - - -class EmbraneOvsPlugin(base.EmbranePlugin, l2.OVSNeutronPluginV2): - '''EmbraneOvsPlugin. - - This plugin uses OpenVSwitch specific L2 plugin for providing L2 networks - and the base EmbranePlugin for L3. - - ''' - _plugin_support = openvswitch_support.OpenvswitchSupport() - - def __init__(self): - '''First run plugin specific initialization, then Embrane's.''' - self._supported_extension_aliases.remove("l3_agent_scheduler") - l2.OVSNeutronPluginV2.__init__(self) - self._run_embrane_config() diff --git a/neutron/plugins/hyperv/__init__.py b/neutron/plugins/hyperv/__init__.py deleted file mode 100644 index 7ef4e09fa..000000000 --- a/neutron/plugins/hyperv/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cloudbase Solutions SRL -# 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. diff --git a/neutron/plugins/hyperv/agent/__init__.py b/neutron/plugins/hyperv/agent/__init__.py deleted file mode 100644 index 7ef4e09fa..000000000 --- a/neutron/plugins/hyperv/agent/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cloudbase Solutions SRL -# 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. diff --git a/neutron/plugins/hyperv/agent/hyperv_neutron_agent.py b/neutron/plugins/hyperv/agent/hyperv_neutron_agent.py deleted file mode 100644 index 07a5ed776..000000000 --- a/neutron/plugins/hyperv/agent/hyperv_neutron_agent.py +++ /dev/null @@ -1,475 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -#Copyright 2013 Cloudbase Solutions SRL -#Copyright 2013 Pedro Navarro Perez -#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: Pedro Navarro Perez -# @author: Alessandro Pilotti, Cloudbase Solutions Srl - -import platform -import re -import sys -import time - -import eventlet -eventlet.monkey_patch() - -from oslo.config import cfg - -from neutron.agent.common import config -from neutron.agent import rpc as agent_rpc -from neutron.agent import securitygroups_rpc as sg_rpc -from neutron.common import config as common_config -from neutron.common import constants as n_const -from neutron.common import rpc_compat -from neutron.common import topics -from neutron import context -from neutron.openstack.common import log as logging -from neutron.openstack.common import loopingcall -from neutron.plugins.common import constants as p_const -from neutron.plugins.hyperv.agent import utils -from neutron.plugins.hyperv.agent import utilsfactory -from neutron.plugins.hyperv.common import constants - -LOG = logging.getLogger(__name__) - -agent_opts = [ - cfg.ListOpt( - 'physical_network_vswitch_mappings', - default=[], - help=_('List of : ' - 'where the physical networks can be expressed with ' - 'wildcards, e.g.: ."*:external"')), - cfg.StrOpt( - 'local_network_vswitch', - default='private', - help=_('Private vswitch name used for local networks')), - cfg.IntOpt('polling_interval', default=2, - help=_("The number of seconds the agent will wait between " - "polling for local device changes.")), - cfg.BoolOpt('enable_metrics_collection', - default=False, - help=_('Enables metrics collections for switch ports by using ' - 'Hyper-V\'s metric APIs. Collected data can by ' - 'retrieved by other apps and services, e.g.: ' - 'Ceilometer. Requires Hyper-V / Windows Server 2012 ' - 'and above')), - cfg.IntOpt('metrics_max_retries', - default=100, - help=_('Specifies the maximum number of retries to enable ' - 'Hyper-V\'s port metrics collection. The agent will try ' - 'to enable the feature once every polling_interval ' - 'period for at most metrics_max_retries or until it ' - 'succeedes.')) -] - - -CONF = cfg.CONF -CONF.register_opts(agent_opts, "AGENT") -config.register_agent_state_opts_helper(cfg.CONF) - - -class HyperVSecurityAgent(rpc_compat.RpcCallback, - sg_rpc.SecurityGroupAgentRpcMixin): - # Set RPC API version to 1.1 by default. - RPC_API_VERSION = '1.1' - - def __init__(self, context, plugin_rpc): - super(HyperVSecurityAgent, self).__init__() - self.context = context - self.plugin_rpc = plugin_rpc - - if sg_rpc.is_firewall_enabled(): - self.init_firewall() - self._setup_rpc() - - def _setup_rpc(self): - self.topic = topics.AGENT - self.endpoints = [HyperVSecurityCallbackMixin(self)] - consumers = [[topics.SECURITY_GROUP, topics.UPDATE]] - - self.connection = agent_rpc.create_consumers(self.endpoints, - self.topic, - consumers) - - -class HyperVSecurityCallbackMixin(rpc_compat.RpcCallback, - sg_rpc.SecurityGroupAgentRpcCallbackMixin): - # Set RPC API version to 1.1 by default. - RPC_API_VERSION = '1.1' - - def __init__(self, sg_agent): - super(HyperVSecurityCallbackMixin, self).__init__() - self.sg_agent = sg_agent - - -class HyperVPluginApi(agent_rpc.PluginApi, - sg_rpc.SecurityGroupServerRpcApiMixin): - pass - - -class HyperVNeutronAgent(rpc_compat.RpcCallback): - # Set RPC API version to 1.0 by default. - RPC_API_VERSION = '1.0' - - def __init__(self): - super(HyperVNeutronAgent, self).__init__() - self._utils = utilsfactory.get_hypervutils() - self._polling_interval = CONF.AGENT.polling_interval - self._load_physical_network_mappings() - self._network_vswitch_map = {} - self._port_metric_retries = {} - self._set_agent_state() - self._setup_rpc() - - def _set_agent_state(self): - self.agent_state = { - 'binary': 'neutron-hyperv-agent', - 'host': cfg.CONF.host, - 'topic': n_const.L2_AGENT_TOPIC, - 'configurations': {'vswitch_mappings': - self._physical_network_mappings}, - 'agent_type': n_const.AGENT_TYPE_HYPERV, - 'start_flag': True} - - def _report_state(self): - try: - self.state_rpc.report_state(self.context, - self.agent_state) - self.agent_state.pop('start_flag', None) - except Exception as ex: - LOG.exception(_("Failed reporting state! %s"), ex) - - def _setup_rpc(self): - self.agent_id = 'hyperv_%s' % platform.node() - self.topic = topics.AGENT - self.plugin_rpc = HyperVPluginApi(topics.PLUGIN) - - self.state_rpc = agent_rpc.PluginReportStateAPI(topics.PLUGIN) - - # RPC network init - self.context = context.get_admin_context_without_session() - # Handle updates from service - self.endpoints = [self] - # Define the listening consumers for the agent - consumers = [[topics.PORT, topics.UPDATE], - [topics.NETWORK, topics.DELETE], - [topics.PORT, topics.DELETE], - [constants.TUNNEL, topics.UPDATE]] - self.connection = agent_rpc.create_consumers(self.endpoints, - self.topic, - consumers) - - self.sec_groups_agent = HyperVSecurityAgent( - self.context, self.plugin_rpc) - report_interval = CONF.AGENT.report_interval - if report_interval: - heartbeat = loopingcall.FixedIntervalLoopingCall( - self._report_state) - heartbeat.start(interval=report_interval) - - def _load_physical_network_mappings(self): - self._physical_network_mappings = {} - for mapping in CONF.AGENT.physical_network_vswitch_mappings: - parts = mapping.split(':') - if len(parts) != 2: - LOG.debug(_('Invalid physical network mapping: %s'), mapping) - else: - pattern = re.escape(parts[0].strip()).replace('\\*', '.*') - vswitch = parts[1].strip() - self._physical_network_mappings[pattern] = vswitch - - def _get_vswitch_for_physical_network(self, phys_network_name): - for pattern in self._physical_network_mappings: - if phys_network_name is None: - phys_network_name = '' - if re.match(pattern, phys_network_name): - return self._physical_network_mappings[pattern] - # Not found in the mappings, the vswitch has the same name - return phys_network_name - - def _get_network_vswitch_map_by_port_id(self, port_id): - for network_id, map in self._network_vswitch_map.iteritems(): - if port_id in map['ports']: - return (network_id, map) - - def network_delete(self, context, network_id=None): - LOG.debug(_("network_delete received. " - "Deleting network %s"), network_id) - # The network may not be defined on this agent - if network_id in self._network_vswitch_map: - self._reclaim_local_network(network_id) - else: - LOG.debug(_("Network %s not defined on agent."), network_id) - - def port_delete(self, context, port_id=None): - LOG.debug(_("port_delete received")) - self._port_unbound(port_id) - - def port_update(self, context, port=None, network_type=None, - segmentation_id=None, physical_network=None): - LOG.debug(_("port_update received")) - if CONF.SECURITYGROUP.enable_security_group: - if 'security_groups' in port: - self.sec_groups_agent.refresh_firewall() - - self._treat_vif_port( - port['id'], port['network_id'], - network_type, physical_network, - segmentation_id, port['admin_state_up']) - - def _get_vswitch_name(self, network_type, physical_network): - if network_type != p_const.TYPE_LOCAL: - vswitch_name = self._get_vswitch_for_physical_network( - physical_network) - else: - vswitch_name = CONF.AGENT.local_network_vswitch - return vswitch_name - - def _provision_network(self, port_id, - net_uuid, network_type, - physical_network, - segmentation_id): - LOG.info(_("Provisioning network %s"), net_uuid) - - vswitch_name = self._get_vswitch_name(network_type, physical_network) - - if network_type in [p_const.TYPE_VLAN, p_const.TYPE_FLAT]: - #Nothing to do - pass - elif network_type == p_const.TYPE_LOCAL: - #TODO(alexpilotti): Check that the switch type is private - #or create it if not existing - pass - else: - raise utils.HyperVException( - msg=(_("Cannot provision unknown network type %(network_type)s" - " for network %(net_uuid)s") % - dict(network_type=network_type, net_uuid=net_uuid))) - - map = { - 'network_type': network_type, - 'vswitch_name': vswitch_name, - 'ports': [], - 'vlan_id': segmentation_id} - self._network_vswitch_map[net_uuid] = map - - def _reclaim_local_network(self, net_uuid): - LOG.info(_("Reclaiming local network %s"), net_uuid) - del self._network_vswitch_map[net_uuid] - - def _port_bound(self, port_id, - net_uuid, - network_type, - physical_network, - segmentation_id): - LOG.debug(_("Binding port %s"), port_id) - - if net_uuid not in self._network_vswitch_map: - self._provision_network( - port_id, net_uuid, network_type, - physical_network, segmentation_id) - - map = self._network_vswitch_map[net_uuid] - map['ports'].append(port_id) - - self._utils.connect_vnic_to_vswitch(map['vswitch_name'], port_id) - - if network_type == p_const.TYPE_VLAN: - LOG.info(_('Binding VLAN ID %(segmentation_id)s ' - 'to switch port %(port_id)s'), - dict(segmentation_id=segmentation_id, port_id=port_id)) - self._utils.set_vswitch_port_vlan_id( - segmentation_id, - port_id) - elif network_type == p_const.TYPE_FLAT: - #Nothing to do - pass - elif network_type == p_const.TYPE_LOCAL: - #Nothing to do - pass - else: - LOG.error(_('Unsupported network type %s'), network_type) - - if CONF.AGENT.enable_metrics_collection: - self._utils.enable_port_metrics_collection(port_id) - self._port_metric_retries[port_id] = CONF.AGENT.metrics_max_retries - - def _port_unbound(self, port_id): - (net_uuid, map) = self._get_network_vswitch_map_by_port_id(port_id) - if net_uuid not in self._network_vswitch_map: - LOG.info(_('Network %s is not avalailable on this agent'), - net_uuid) - return - - LOG.debug(_("Unbinding port %s"), port_id) - self._utils.disconnect_switch_port(map['vswitch_name'], port_id, True) - - if not map['ports']: - self._reclaim_local_network(net_uuid) - - def _port_enable_control_metrics(self): - if not CONF.AGENT.enable_metrics_collection: - return - - for port_id in self._port_metric_retries.keys(): - if self._utils.can_enable_control_metrics(port_id): - self._utils.enable_control_metrics(port_id) - LOG.info(_('Port metrics enabled for port: %s'), port_id) - del self._port_metric_retries[port_id] - elif self._port_metric_retries[port_id] < 1: - self._utils.enable_control_metrics(port_id) - LOG.error(_('Port metrics raw enabling for port: %s'), port_id) - del self._port_metric_retries[port_id] - else: - self._port_metric_retries[port_id] -= 1 - - def _update_ports(self, registered_ports): - ports = self._utils.get_vnic_ids() - if ports == registered_ports: - return - added = ports - registered_ports - removed = registered_ports - ports - return {'current': ports, - 'added': added, - 'removed': removed} - - def _treat_vif_port(self, port_id, network_id, network_type, - physical_network, segmentation_id, - admin_state_up): - if self._utils.vnic_port_exists(port_id): - if admin_state_up: - self._port_bound(port_id, network_id, network_type, - physical_network, segmentation_id) - else: - self._port_unbound(port_id) - else: - LOG.debug(_("No port %s defined on agent."), port_id) - - def _treat_devices_added(self, devices): - resync = False - for device in devices: - LOG.info(_("Adding port %s"), device) - try: - device_details = self.plugin_rpc.get_device_details( - self.context, - device, - self.agent_id) - except Exception as e: - LOG.debug( - _("Unable to get port details for " - "device %(device)s: %(e)s"), - {'device': device, 'e': e}) - resync = True - continue - if 'port_id' in device_details: - LOG.info( - _("Port %(device)s updated. Details: %(device_details)s"), - {'device': device, 'device_details': device_details}) - self._treat_vif_port( - device_details['port_id'], - device_details['network_id'], - device_details['network_type'], - device_details['physical_network'], - device_details['segmentation_id'], - device_details['admin_state_up']) - - # check if security groups is enabled. - # if not, teardown the security group rules - if CONF.SECURITYGROUP.enable_security_group: - self.sec_groups_agent.prepare_devices_filter([device]) - else: - self._utils.remove_all_security_rules( - device_details['port_id']) - self.plugin_rpc.update_device_up(self.context, - device, - self.agent_id, - cfg.CONF.host) - return resync - - def _treat_devices_removed(self, devices): - resync = False - for device in devices: - LOG.info(_("Removing port %s"), device) - try: - self.plugin_rpc.update_device_down(self.context, - device, - self.agent_id, - cfg.CONF.host) - except Exception as e: - LOG.debug( - _("Removing port failed for device %(device)s: %(e)s"), - dict(device=device, e=e)) - resync = True - continue - self._port_unbound(device) - return resync - - def _process_network_ports(self, port_info): - resync_a = False - resync_b = False - if 'added' in port_info: - resync_a = self._treat_devices_added(port_info['added']) - if 'removed' in port_info: - resync_b = self._treat_devices_removed(port_info['removed']) - # If one of the above operations fails => resync with plugin - return (resync_a | resync_b) - - def daemon_loop(self): - sync = True - ports = set() - - while True: - try: - start = time.time() - if sync: - LOG.info(_("Agent out of sync with plugin!")) - ports.clear() - sync = False - - port_info = self._update_ports(ports) - - # notify plugin about port deltas - if port_info: - LOG.debug(_("Agent loop has new devices!")) - # If treat devices fails - must resync with plugin - sync = self._process_network_ports(port_info) - ports = port_info['current'] - - self._port_enable_control_metrics() - except Exception as e: - LOG.exception(_("Error in agent event loop: %s"), e) - sync = True - - # sleep till end of polling interval - elapsed = (time.time() - start) - if (elapsed < self._polling_interval): - time.sleep(self._polling_interval - elapsed) - else: - LOG.debug(_("Loop iteration exceeded interval " - "(%(polling_interval)s vs. %(elapsed)s)"), - {'polling_interval': self._polling_interval, - 'elapsed': elapsed}) - - -def main(): - common_config.init(sys.argv[1:]) - common_config.setup_logging(cfg.CONF) - - plugin = HyperVNeutronAgent() - - # Start everything. - LOG.info(_("Agent initialized successfully, now running... ")) - plugin.daemon_loop() diff --git a/neutron/plugins/hyperv/agent/security_groups_driver.py b/neutron/plugins/hyperv/agent/security_groups_driver.py deleted file mode 100644 index 755ab5270..000000000 --- a/neutron/plugins/hyperv/agent/security_groups_driver.py +++ /dev/null @@ -1,146 +0,0 @@ -#Copyright 2014 Cloudbase Solutions SRL -#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: Claudiu Belu, Cloudbase Solutions Srl - -from neutron.agent import firewall -from neutron.openstack.common import log as logging -from neutron.plugins.hyperv.agent import utilsfactory -from neutron.plugins.hyperv.agent import utilsv2 - -LOG = logging.getLogger(__name__) - - -class HyperVSecurityGroupsDriver(firewall.FirewallDriver): - """Security Groups Driver. - - Security Groups implementation for Hyper-V VMs. - """ - - _ACL_PROP_MAP = { - 'direction': {'ingress': utilsv2.HyperVUtilsV2._ACL_DIR_IN, - 'egress': utilsv2.HyperVUtilsV2._ACL_DIR_OUT}, - 'ethertype': {'IPv4': utilsv2.HyperVUtilsV2._ACL_TYPE_IPV4, - 'IPv6': utilsv2.HyperVUtilsV2._ACL_TYPE_IPV6}, - 'protocol': {'icmp': utilsv2.HyperVUtilsV2._ICMP_PROTOCOL}, - 'default': "ANY", - 'address_default': {'IPv4': '0.0.0.0/0', 'IPv6': '::/0'} - } - - def __init__(self): - self._utils = utilsfactory.get_hypervutils() - self._security_ports = {} - - def prepare_port_filter(self, port): - LOG.debug('Creating port %s rules' % len(port['security_group_rules'])) - - # newly created port, add default rules. - if port['device'] not in self._security_ports: - LOG.debug('Creating default reject rules.') - self._utils.create_default_reject_all_rules(port['id']) - - self._security_ports[port['device']] = port - self._create_port_rules(port['id'], port['security_group_rules']) - - def _create_port_rules(self, port_id, rules): - for rule in rules: - param_map = self._create_param_map(rule) - try: - self._utils.create_security_rule(port_id, **param_map) - except Exception as ex: - LOG.error(_('Hyper-V Exception: %(hyperv_exeption)s while ' - 'adding rule: %(rule)s'), - dict(hyperv_exeption=ex, rule=rule)) - - def _remove_port_rules(self, port_id, rules): - for rule in rules: - param_map = self._create_param_map(rule) - try: - self._utils.remove_security_rule(port_id, **param_map) - except Exception as ex: - LOG.error(_('Hyper-V Exception: %(hyperv_exeption)s while ' - 'removing rule: %(rule)s'), - dict(hyperv_exeption=ex, rule=rule)) - - def _create_param_map(self, rule): - if 'port_range_min' in rule and 'port_range_max' in rule: - local_port = '%s-%s' % (rule['port_range_min'], - rule['port_range_max']) - else: - local_port = self._ACL_PROP_MAP['default'] - - return { - 'direction': self._ACL_PROP_MAP['direction'][rule['direction']], - 'acl_type': self._ACL_PROP_MAP['ethertype'][rule['ethertype']], - 'local_port': local_port, - 'protocol': self._get_rule_protocol(rule), - 'remote_address': self._get_rule_remote_address(rule) - } - - def apply_port_filter(self, port): - LOG.info(_('Aplying port filter.')) - - def update_port_filter(self, port): - LOG.info(_('Updating port rules.')) - - if port['device'] not in self._security_ports: - self.prepare_port_filter(port) - return - - old_port = self._security_ports[port['device']] - rules = old_port['security_group_rules'] - param_port_rules = port['security_group_rules'] - - new_rules = [r for r in param_port_rules if r not in rules] - remove_rules = [r for r in rules if r not in param_port_rules] - - LOG.info(_("Creating %(new)s new rules, removing %(old)s " - "old rules."), - {'new': len(new_rules), - 'old': len(remove_rules)}) - - self._remove_port_rules(old_port['id'], remove_rules) - self._create_port_rules(port['id'], new_rules) - - self._security_ports[port['device']] = port - - def remove_port_filter(self, port): - LOG.info(_('Removing port filter')) - self._security_ports.pop(port['device'], None) - - @property - def ports(self): - return self._security_ports - - def _get_rule_remote_address(self, rule): - if rule['direction'] is 'ingress': - ip_prefix = 'source_ip_prefix' - else: - ip_prefix = 'dest_ip_prefix' - - if ip_prefix in rule: - return rule[ip_prefix] - return self._ACL_PROP_MAP['address_default'][rule['ethertype']] - - def _get_rule_protocol(self, rule): - protocol = self._get_rule_prop_or_default(rule, 'protocol') - if protocol in self._ACL_PROP_MAP['protocol'].keys(): - return self._ACL_PROP_MAP['protocol'][protocol] - - return protocol - - def _get_rule_prop_or_default(self, rule, prop): - if prop in rule: - return rule[prop] - return self._ACL_PROP_MAP['default'] diff --git a/neutron/plugins/hyperv/agent/utils.py b/neutron/plugins/hyperv/agent/utils.py deleted file mode 100644 index 31439f0b0..000000000 --- a/neutron/plugins/hyperv/agent/utils.py +++ /dev/null @@ -1,256 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cloudbase Solutions SRL -# Copyright 2013 Pedro Navarro Perez -# 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: Pedro Navarro Perez -# @author: Alessandro Pilotti, Cloudbase Solutions Srl - -import sys -import time - -from oslo.config import cfg - -from neutron.common import exceptions as n_exc -from neutron.openstack.common import log as logging - -# Check needed for unit testing on Unix -if sys.platform == 'win32': - import wmi - -CONF = cfg.CONF -LOG = logging.getLogger(__name__) - - -class HyperVException(n_exc.NeutronException): - message = _('HyperVException: %(msg)s') - -WMI_JOB_STATE_STARTED = 4096 -WMI_JOB_STATE_RUNNING = 4 -WMI_JOB_STATE_COMPLETED = 7 - - -class HyperVUtils(object): - - _ETHERNET_SWITCH_PORT = 'Msvm_SwitchPort' - - _wmi_namespace = '//./root/virtualization' - - def __init__(self): - self._wmi_conn = None - - @property - def _conn(self): - if self._wmi_conn is None: - self._wmi_conn = wmi.WMI(moniker=self._wmi_namespace) - return self._wmi_conn - - def get_switch_ports(self, vswitch_name): - vswitch = self._get_vswitch(vswitch_name) - vswitch_ports = vswitch.associators( - wmi_result_class=self._ETHERNET_SWITCH_PORT) - return set(p.Name for p in vswitch_ports) - - def vnic_port_exists(self, port_id): - try: - self._get_vnic_settings(port_id) - except Exception: - return False - return True - - def get_vnic_ids(self): - return set( - p.ElementName - for p in self._conn.Msvm_SyntheticEthernetPortSettingData() - if p.ElementName is not None) - - def _get_vnic_settings(self, vnic_name): - vnic_settings = self._conn.Msvm_SyntheticEthernetPortSettingData( - ElementName=vnic_name) - if not vnic_settings: - raise HyperVException(msg=_('Vnic not found: %s') % vnic_name) - return vnic_settings[0] - - def connect_vnic_to_vswitch(self, vswitch_name, switch_port_name): - vnic_settings = self._get_vnic_settings(switch_port_name) - if not vnic_settings.Connection or not vnic_settings.Connection[0]: - port = self.get_port_by_id(switch_port_name, vswitch_name) - if port: - port_path = port.Path_() - else: - port_path = self._create_switch_port( - vswitch_name, switch_port_name) - vnic_settings.Connection = [port_path] - self._modify_virt_resource(vnic_settings) - - def _get_vm_from_res_setting_data(self, res_setting_data): - sd = res_setting_data.associators( - wmi_result_class='Msvm_VirtualSystemSettingData') - vm = sd[0].associators( - wmi_result_class='Msvm_ComputerSystem') - return vm[0] - - def _modify_virt_resource(self, res_setting_data): - vm = self._get_vm_from_res_setting_data(res_setting_data) - - vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] - (job_path, ret_val) = vs_man_svc.ModifyVirtualSystemResources( - vm.Path_(), [res_setting_data.GetText_(1)]) - self._check_job_status(ret_val, job_path) - - def _check_job_status(self, ret_val, jobpath): - """Poll WMI job state for completion.""" - if not ret_val: - return - elif ret_val not in [WMI_JOB_STATE_STARTED, WMI_JOB_STATE_RUNNING]: - raise HyperVException(msg=_('Job failed with error %d') % ret_val) - - job_wmi_path = jobpath.replace('\\', '/') - job = wmi.WMI(moniker=job_wmi_path) - - while job.JobState == WMI_JOB_STATE_RUNNING: - time.sleep(0.1) - job = wmi.WMI(moniker=job_wmi_path) - if job.JobState != WMI_JOB_STATE_COMPLETED: - job_state = job.JobState - if job.path().Class == "Msvm_ConcreteJob": - err_sum_desc = job.ErrorSummaryDescription - err_desc = job.ErrorDescription - err_code = job.ErrorCode - data = {'job_state': job_state, - 'err_sum_desc': err_sum_desc, - 'err_desc': err_desc, - 'err_code': err_code} - raise HyperVException( - msg=_("WMI job failed with status %(job_state)d. " - "Error details: %(err_sum_desc)s - %(err_desc)s - " - "Error code: %(err_code)d") % data) - else: - (error, ret_val) = job.GetError() - if not ret_val and error: - data = {'job_state': job_state, - 'error': error} - raise HyperVException( - msg=_("WMI job failed with status %(job_state)d. " - "Error details: %(error)s") % data) - else: - raise HyperVException( - msg=_("WMI job failed with status %d. " - "No error description available") % job_state) - - desc = job.Description - elap = job.ElapsedTime - LOG.debug(_("WMI job succeeded: %(desc)s, Elapsed=%(elap)s"), - {'desc': desc, 'elap': elap}) - - def _create_switch_port(self, vswitch_name, switch_port_name): - """Creates a switch port.""" - switch_svc = self._conn.Msvm_VirtualSwitchManagementService()[0] - vswitch_path = self._get_vswitch(vswitch_name).path_() - (new_port, ret_val) = switch_svc.CreateSwitchPort( - Name=switch_port_name, - FriendlyName=switch_port_name, - ScopeOfResidence="", - VirtualSwitch=vswitch_path) - if ret_val != 0: - raise HyperVException( - msg=_('Failed creating port for %s') % vswitch_name) - return new_port - - def disconnect_switch_port( - self, vswitch_name, switch_port_name, delete_port): - """Disconnects the switch port.""" - switch_svc = self._conn.Msvm_VirtualSwitchManagementService()[0] - switch_port_path = self._get_switch_port_path_by_name( - switch_port_name) - if not switch_port_path: - # Port not found. It happens when the VM was already deleted. - return - - (ret_val, ) = switch_svc.DisconnectSwitchPort( - SwitchPort=switch_port_path) - if ret_val != 0: - data = {'switch_port_name': switch_port_name, - 'vswitch_name': vswitch_name, - 'ret_val': ret_val} - raise HyperVException( - msg=_('Failed to disconnect port %(switch_port_name)s ' - 'from switch %(vswitch_name)s ' - 'with error %(ret_val)s') % data) - if delete_port: - (ret_val, ) = switch_svc.DeleteSwitchPort( - SwitchPort=switch_port_path) - if ret_val != 0: - data = {'switch_port_name': switch_port_name, - 'vswitch_name': vswitch_name, - 'ret_val': ret_val} - raise HyperVException( - msg=_('Failed to delete port %(switch_port_name)s ' - 'from switch %(vswitch_name)s ' - 'with error %(ret_val)s') % data) - - def _get_vswitch(self, vswitch_name): - vswitch = self._conn.Msvm_VirtualSwitch(ElementName=vswitch_name) - if not vswitch: - raise HyperVException(msg=_('VSwitch not found: %s') % - vswitch_name) - return vswitch[0] - - def _get_vswitch_external_port(self, vswitch): - vswitch_ports = vswitch.associators( - wmi_result_class=self._ETHERNET_SWITCH_PORT) - for vswitch_port in vswitch_ports: - lan_endpoints = vswitch_port.associators( - wmi_result_class='Msvm_SwitchLanEndpoint') - if lan_endpoints: - ext_port = lan_endpoints[0].associators( - wmi_result_class='Msvm_ExternalEthernetPort') - if ext_port: - return vswitch_port - - def set_vswitch_port_vlan_id(self, vlan_id, switch_port_name): - vlan_endpoint_settings = self._conn.Msvm_VLANEndpointSettingData( - ElementName=switch_port_name)[0] - if vlan_endpoint_settings.AccessVLAN != vlan_id: - vlan_endpoint_settings.AccessVLAN = vlan_id - vlan_endpoint_settings.put() - - def _get_switch_port_path_by_name(self, switch_port_name): - vswitch = self._conn.Msvm_SwitchPort(ElementName=switch_port_name) - if vswitch: - return vswitch[0].path_() - - def get_vswitch_id(self, vswitch_name): - vswitch = self._get_vswitch(vswitch_name) - return vswitch.Name - - def get_port_by_id(self, port_id, vswitch_name): - vswitch = self._get_vswitch(vswitch_name) - switch_ports = vswitch.associators( - wmi_result_class=self._ETHERNET_SWITCH_PORT) - for switch_port in switch_ports: - if (switch_port.ElementName == port_id): - return switch_port - - def enable_port_metrics_collection(self, switch_port_name): - raise NotImplementedError(_("Metrics collection is not supported on " - "this version of Hyper-V")) - - def enable_control_metrics(self, switch_port_name): - raise NotImplementedError(_("Metrics collection is not supported on " - "this version of Hyper-V")) - - def can_enable_control_metrics(self, switch_port_name): - return False diff --git a/neutron/plugins/hyperv/agent/utilsfactory.py b/neutron/plugins/hyperv/agent/utilsfactory.py deleted file mode 100644 index 5698255c3..000000000 --- a/neutron/plugins/hyperv/agent/utilsfactory.py +++ /dev/null @@ -1,72 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cloudbase Solutions SRL -# 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: Claudiu Belu, Cloudbase Solutions Srl - -import sys - -from oslo.config import cfg - -from neutron.openstack.common import log as logging -from neutron.plugins.hyperv.agent import utils -from neutron.plugins.hyperv.agent import utilsv2 - -# Check needed for unit testing on Unix -if sys.platform == 'win32': - import wmi - -hyper_opts = [ - cfg.BoolOpt('force_hyperv_utils_v1', - default=False, - help=_('Force V1 WMI utility classes')), -] - -CONF = cfg.CONF -CONF.register_opts(hyper_opts, 'hyperv') - -LOG = logging.getLogger(__name__) - - -def _get_windows_version(): - return wmi.WMI(moniker='//./root/cimv2').Win32_OperatingSystem()[0].Version - - -def _check_min_windows_version(major, minor, build=0): - version_str = _get_windows_version() - return map(int, version_str.split('.')) >= [major, minor, build] - - -def get_hypervutils(): - # V1 virtualization namespace features are supported up to - # Windows Server / Hyper-V Server 2012 - # V2 virtualization namespace features are supported starting with - # Windows Server / Hyper-V Server 2012 - # Windows Server / Hyper-V Server 2012 R2 uses the V2 namespace and - # introduces additional features - - force_v1_flag = CONF.hyperv.force_hyperv_utils_v1 - if _check_min_windows_version(6, 3): - if force_v1_flag: - LOG.warning(_('V1 virtualization namespace no longer supported on ' - 'Windows Server / Hyper-V Server 2012 R2 or above.')) - cls = utilsv2.HyperVUtilsV2R2 - elif not force_v1_flag and _check_min_windows_version(6, 2): - cls = utilsv2.HyperVUtilsV2 - else: - cls = utils.HyperVUtils - LOG.debug(_("Loading class: %(module_name)s.%(class_name)s"), - {'module_name': cls.__module__, 'class_name': cls.__name__}) - return cls() diff --git a/neutron/plugins/hyperv/agent/utilsv2.py b/neutron/plugins/hyperv/agent/utilsv2.py deleted file mode 100644 index a55839487..000000000 --- a/neutron/plugins/hyperv/agent/utilsv2.py +++ /dev/null @@ -1,439 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cloudbase Solutions SRL -# 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: Alessandro Pilotti, Cloudbase Solutions Srl -# @author: Claudiu Belu, Cloudbase Solutions Srl - -from neutron.plugins.hyperv.agent import utils - - -class HyperVUtilsV2(utils.HyperVUtils): - - _EXTERNAL_PORT = 'Msvm_ExternalEthernetPort' - _ETHERNET_SWITCH_PORT = 'Msvm_EthernetSwitchPort' - _PORT_ALLOC_SET_DATA = 'Msvm_EthernetPortAllocationSettingData' - _PORT_VLAN_SET_DATA = 'Msvm_EthernetSwitchPortVlanSettingData' - _PORT_SECURITY_SET_DATA = 'Msvm_EthernetSwitchPortSecuritySettingData' - _PORT_ALLOC_ACL_SET_DATA = 'Msvm_EthernetSwitchPortAclSettingData' - _PORT_EXT_ACL_SET_DATA = _PORT_ALLOC_ACL_SET_DATA - _LAN_ENDPOINT = 'Msvm_LANEndpoint' - _STATE_DISABLED = 3 - _OPERATION_MODE_ACCESS = 1 - - _VIRTUAL_SYSTEM_SETTING_DATA = 'Msvm_VirtualSystemSettingData' - _VM_SUMMARY_ENABLED_STATE = 100 - _HYPERV_VM_STATE_ENABLED = 2 - - _ACL_DIR_IN = 1 - _ACL_DIR_OUT = 2 - - _ACL_TYPE_IPV4 = 2 - _ACL_TYPE_IPV6 = 3 - - _ACL_ACTION_ALLOW = 1 - _ACL_ACTION_DENY = 2 - _ACL_ACTION_METER = 3 - - _METRIC_ENABLED = 2 - _NET_IN_METRIC_NAME = 'Filtered Incoming Network Traffic' - _NET_OUT_METRIC_NAME = 'Filtered Outgoing Network Traffic' - - _ACL_APPLICABILITY_LOCAL = 1 - _ACL_APPLICABILITY_REMOTE = 2 - - _ACL_DEFAULT = 'ANY' - _IPV4_ANY = '0.0.0.0/0' - _IPV6_ANY = '::/0' - _TCP_PROTOCOL = 'tcp' - _UDP_PROTOCOL = 'udp' - _ICMP_PROTOCOL = '1' - _MAX_WEIGHT = 65500 - - # 2 directions x 2 address types = 4 ACLs - _REJECT_ACLS_COUNT = 4 - - _wmi_namespace = '//./root/virtualization/v2' - - def __init__(self): - super(HyperVUtilsV2, self).__init__() - - def connect_vnic_to_vswitch(self, vswitch_name, switch_port_name): - vnic = self._get_vnic_settings(switch_port_name) - vswitch = self._get_vswitch(vswitch_name) - - port, found = self._get_switch_port_allocation(switch_port_name, True) - port.HostResource = [vswitch.path_()] - port.Parent = vnic.path_() - if not found: - vm = self._get_vm_from_res_setting_data(vnic) - self._add_virt_resource(vm, port) - else: - self._modify_virt_resource(port) - - def _modify_virt_resource(self, res_setting_data): - vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] - (job_path, out_set_data, ret_val) = vs_man_svc.ModifyResourceSettings( - ResourceSettings=[res_setting_data.GetText_(1)]) - self._check_job_status(ret_val, job_path) - - def _add_virt_resource(self, vm, res_setting_data): - vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] - (job_path, out_set_data, ret_val) = vs_man_svc.AddResourceSettings( - vm.path_(), [res_setting_data.GetText_(1)]) - self._check_job_status(ret_val, job_path) - - def _remove_virt_resource(self, res_setting_data): - vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] - (job, ret_val) = vs_man_svc.RemoveResourceSettings( - ResourceSettings=[res_setting_data.path_()]) - self._check_job_status(ret_val, job) - - def _add_virt_feature(self, element, res_setting_data): - vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] - (job_path, out_set_data, ret_val) = vs_man_svc.AddFeatureSettings( - element.path_(), [res_setting_data.GetText_(1)]) - self._check_job_status(ret_val, job_path) - - def _remove_virt_feature(self, feature_resource): - self._remove_multiple_virt_features([feature_resource]) - - def _remove_multiple_virt_features(self, feature_resources): - vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] - (job_path, ret_val) = vs_man_svc.RemoveFeatureSettings( - FeatureSettings=[f.path_() for f in feature_resources]) - self._check_job_status(ret_val, job_path) - - def disconnect_switch_port( - self, vswitch_name, switch_port_name, delete_port): - """Disconnects the switch port.""" - sw_port, found = self._get_switch_port_allocation(switch_port_name) - if not sw_port: - # Port not found. It happens when the VM was already deleted. - return - - if delete_port: - self._remove_virt_resource(sw_port) - else: - sw_port.EnabledState = self._STATE_DISABLED - self._modify_virt_resource(sw_port) - - def _get_vswitch(self, vswitch_name): - vswitch = self._conn.Msvm_VirtualEthernetSwitch( - ElementName=vswitch_name) - if not len(vswitch): - raise utils.HyperVException(msg=_('VSwitch not found: %s') % - vswitch_name) - return vswitch[0] - - def _get_vswitch_external_port(self, vswitch): - vswitch_ports = vswitch.associators( - wmi_result_class=self._ETHERNET_SWITCH_PORT) - for vswitch_port in vswitch_ports: - lan_endpoints = vswitch_port.associators( - wmi_result_class=self._LAN_ENDPOINT) - if len(lan_endpoints): - lan_endpoints = lan_endpoints[0].associators( - wmi_result_class=self._LAN_ENDPOINT) - if len(lan_endpoints): - ext_port = lan_endpoints[0].associators( - wmi_result_class=self._EXTERNAL_PORT) - if ext_port: - return vswitch_port - - def set_vswitch_port_vlan_id(self, vlan_id, switch_port_name): - port_alloc, found = self._get_switch_port_allocation(switch_port_name) - if not found: - raise utils.HyperVException( - msg=_('Port Allocation not found: %s') % switch_port_name) - - vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] - vlan_settings = self._get_vlan_setting_data_from_port_alloc(port_alloc) - if vlan_settings: - # Removing the feature because it cannot be modified - # due to a wmi exception. - (job_path, ret_val) = vs_man_svc.RemoveFeatureSettings( - FeatureSettings=[vlan_settings.path_()]) - self._check_job_status(ret_val, job_path) - - (vlan_settings, found) = self._get_vlan_setting_data(switch_port_name) - vlan_settings.AccessVlanId = vlan_id - vlan_settings.OperationMode = self._OPERATION_MODE_ACCESS - (job_path, out, ret_val) = vs_man_svc.AddFeatureSettings( - port_alloc.path_(), [vlan_settings.GetText_(1)]) - self._check_job_status(ret_val, job_path) - - def _get_vlan_setting_data_from_port_alloc(self, port_alloc): - return self._get_first_item(port_alloc.associators( - wmi_result_class=self._PORT_VLAN_SET_DATA)) - - def _get_vlan_setting_data(self, switch_port_name, create=True): - return self._get_setting_data( - self._PORT_VLAN_SET_DATA, - switch_port_name, create) - - def _get_switch_port_allocation(self, switch_port_name, create=False): - return self._get_setting_data( - self._PORT_ALLOC_SET_DATA, - switch_port_name, create) - - def _get_setting_data(self, class_name, element_name, create=True): - element_name = element_name.replace("'", '"') - q = self._conn.query("SELECT * FROM %(class_name)s WHERE " - "ElementName = '%(element_name)s'" % - {"class_name": class_name, - "element_name": element_name}) - data = self._get_first_item(q) - found = data is not None - if not data and create: - data = self._get_default_setting_data(class_name) - data.ElementName = element_name - return data, found - - def _get_default_setting_data(self, class_name): - return self._conn.query("SELECT * FROM %s WHERE InstanceID " - "LIKE '%%\\Default'" % class_name)[0] - - def _get_first_item(self, obj): - if obj: - return obj[0] - - def enable_port_metrics_collection(self, switch_port_name): - port, found = self._get_switch_port_allocation(switch_port_name, False) - if not found: - return - - # Add the ACLs only if they don't already exist - acls = port.associators(wmi_result_class=self._PORT_ALLOC_ACL_SET_DATA) - for acl_type in [self._ACL_TYPE_IPV4, self._ACL_TYPE_IPV6]: - for acl_dir in [self._ACL_DIR_IN, self._ACL_DIR_OUT]: - _acls = self._filter_acls( - acls, self._ACL_ACTION_METER, acl_dir, acl_type) - - if not _acls: - acl = self._create_acl( - acl_dir, acl_type, self._ACL_ACTION_METER) - self._add_virt_feature(port, acl) - - def enable_control_metrics(self, switch_port_name): - port, found = self._get_switch_port_allocation(switch_port_name, False) - if not found: - return - - metric_svc = self._conn.Msvm_MetricService()[0] - metric_names = [self._NET_IN_METRIC_NAME, self._NET_OUT_METRIC_NAME] - - for metric_name in metric_names: - metric_def = self._conn.CIM_BaseMetricDefinition(Name=metric_name) - if metric_def: - metric_svc.ControlMetrics( - Subject=port.path_(), - Definition=metric_def[0].path_(), - MetricCollectionEnabled=self._METRIC_ENABLED) - - def can_enable_control_metrics(self, switch_port_name): - port, found = self._get_switch_port_allocation(switch_port_name, False) - if not found: - return False - - if not self._is_port_vm_started(port): - return False - - # all 4 meter ACLs must be existent first. (2 x direction) - acls = port.associators(wmi_result_class=self._PORT_ALLOC_ACL_SET_DATA) - acls = [a for a in acls if a.Action == self._ACL_ACTION_METER] - if len(acls) < 2: - return False - return True - - def _is_port_vm_started(self, port): - vs_man_svc = self._conn.Msvm_VirtualSystemManagementService()[0] - vmsettings = port.associators( - wmi_result_class=self._VIRTUAL_SYSTEM_SETTING_DATA) - #See http://msdn.microsoft.com/en-us/library/cc160706%28VS.85%29.aspx - (ret_val, summary_info) = vs_man_svc.GetSummaryInformation( - [self._VM_SUMMARY_ENABLED_STATE], - [v.path_() for v in vmsettings]) - if ret_val or not summary_info: - raise utils.HyperVException(msg=_('Cannot get VM summary data ' - 'for: %s') % port.ElementName) - - return summary_info[0].EnabledState is self._HYPERV_VM_STATE_ENABLED - - def create_security_rule(self, switch_port_name, direction, acl_type, - local_port, protocol, remote_address): - port, found = self._get_switch_port_allocation(switch_port_name, False) - if not found: - return - - # Add the ACLs only if they don't already exist - acls = port.associators(wmi_result_class=self._PORT_EXT_ACL_SET_DATA) - weight = self._get_new_weight(acls) - self._bind_security_rule( - port, direction, acl_type, self._ACL_ACTION_ALLOW, local_port, - protocol, remote_address, weight) - - def remove_security_rule(self, switch_port_name, direction, acl_type, - local_port, protocol, remote_address): - port, found = self._get_switch_port_allocation(switch_port_name, False) - if not found: - # Port not found. It happens when the VM was already deleted. - return - - acls = port.associators(wmi_result_class=self._PORT_EXT_ACL_SET_DATA) - filtered_acls = self._filter_security_acls( - acls, self._ACL_ACTION_ALLOW, direction, acl_type, local_port, - protocol, remote_address) - - for acl in filtered_acls: - self._remove_virt_feature(acl) - - def remove_all_security_rules(self, switch_port_name): - port, found = self._get_switch_port_allocation(switch_port_name, False) - if not found: - # Port not found. It happens when the VM was already deleted. - return - - acls = port.associators(wmi_result_class=self._PORT_EXT_ACL_SET_DATA) - filtered_acls = [a for a in acls if - a.Action is not self._ACL_ACTION_METER] - - if filtered_acls: - self._remove_multiple_virt_features(filtered_acls) - - def create_default_reject_all_rules(self, switch_port_name): - port, found = self._get_switch_port_allocation(switch_port_name, False) - if not found: - raise utils.HyperVException( - msg=_('Port Allocation not found: %s') % switch_port_name) - - acls = port.associators(wmi_result_class=self._PORT_EXT_ACL_SET_DATA) - filtered_acls = [v for v in acls if v.Action == self._ACL_ACTION_DENY] - - if len(filtered_acls) >= self._REJECT_ACLS_COUNT: - return - - for acl in filtered_acls: - self._remove_virt_feature(acl) - - weight = 0 - ipv4_pair = (self._ACL_TYPE_IPV4, self._IPV4_ANY) - ipv6_pair = (self._ACL_TYPE_IPV6, self._IPV6_ANY) - for direction in [self._ACL_DIR_IN, self._ACL_DIR_OUT]: - for acl_type, address in [ipv4_pair, ipv6_pair]: - for protocol in [self._TCP_PROTOCOL, - self._UDP_PROTOCOL, - self._ICMP_PROTOCOL]: - self._bind_security_rule( - port, direction, acl_type, self._ACL_ACTION_DENY, - self._ACL_DEFAULT, protocol, address, weight) - weight += 1 - - def _bind_security_rule(self, port, direction, acl_type, action, - local_port, protocol, remote_address, weight): - acls = port.associators(wmi_result_class=self._PORT_EXT_ACL_SET_DATA) - filtered_acls = self._filter_security_acls( - acls, action, direction, acl_type, local_port, protocol, - remote_address) - - for acl in filtered_acls: - self._remove_virt_feature(acl) - - acl = self._create_security_acl( - direction, acl_type, action, local_port, protocol, remote_address, - weight) - - self._add_virt_feature(port, acl) - - def _create_acl(self, direction, acl_type, action): - acl = self._get_default_setting_data(self._PORT_ALLOC_ACL_SET_DATA) - acl.set(Direction=direction, - AclType=acl_type, - Action=action, - Applicability=self._ACL_APPLICABILITY_LOCAL) - return acl - - def _create_security_acl(self, direction, acl_type, action, local_port, - protocol, remote_ip_address, weight): - acl = self._create_acl(direction, acl_type, action) - (remote_address, remote_prefix_length) = remote_ip_address.split('/') - acl.set(Applicability=self._ACL_APPLICABILITY_REMOTE, - RemoteAddress=remote_address, - RemoteAddressPrefixLength=remote_prefix_length) - return acl - - def _filter_acls(self, acls, action, direction, acl_type, remote_addr=""): - return [v for v in acls - if v.Action == action and - v.Direction == direction and - v.AclType == acl_type and - v.RemoteAddress == remote_addr] - - def _filter_security_acls(self, acls, acl_action, direction, acl_type, - local_port, protocol, remote_addr=""): - (remote_address, remote_prefix_length) = remote_addr.split('/') - remote_prefix_length = int(remote_prefix_length) - - return [v for v in acls - if v.Direction == direction and - v.Action in [self._ACL_ACTION_ALLOW, self._ACL_ACTION_DENY] and - v.AclType == acl_type and - v.RemoteAddress == remote_address and - v.RemoteAddressPrefixLength == remote_prefix_length] - - def _get_new_weight(self, acls): - return 0 - - -class HyperVUtilsV2R2(HyperVUtilsV2): - _PORT_EXT_ACL_SET_DATA = 'Msvm_EthernetSwitchPortExtendedAclSettingData' - _MAX_WEIGHT = 65500 - - # 2 directions x 2 address types x 3 protocols = 12 ACLs - _REJECT_ACLS_COUNT = 12 - - def _create_security_acl(self, direction, acl_type, action, local_port, - protocol, remote_addr, weight): - acl = self._get_default_setting_data(self._PORT_EXT_ACL_SET_DATA) - acl.set(Direction=direction, - Action=action, - LocalPort=str(local_port), - Protocol=protocol, - RemoteIPAddress=remote_addr, - IdleSessionTimeout=0, - Weight=weight) - return acl - - def _filter_security_acls(self, acls, action, direction, acl_type, - local_port, protocol, remote_addr=""): - return [v for v in acls - if v.Action == action and - v.Direction == direction and - v.LocalPort == str(local_port) and - v.Protocol == protocol and - v.RemoteIPAddress == remote_addr] - - def _get_new_weight(self, acls): - acls = [a for a in acls if a.Action is not self._ACL_ACTION_DENY] - if not acls: - return self._MAX_WEIGHT - 1 - - weights = [a.Weight for a in acls] - min_weight = min(weights) - for weight in range(min_weight, self._MAX_WEIGHT): - if weight not in weights: - return weight - - return min_weight - 1 diff --git a/neutron/plugins/hyperv/agent_notifier_api.py b/neutron/plugins/hyperv/agent_notifier_api.py deleted file mode 100644 index 058d96c4c..000000000 --- a/neutron/plugins/hyperv/agent_notifier_api.py +++ /dev/null @@ -1,80 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cloudbase Solutions SRL -# 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: Alessandro Pilotti, Cloudbase Solutions Srl - -from neutron.common import rpc_compat -from neutron.common import topics -from neutron.openstack.common import log as logging -from neutron.plugins.hyperv.common import constants - -LOG = logging.getLogger(__name__) - - -class AgentNotifierApi(rpc_compat.RpcProxy): - '''Agent side of the openvswitch rpc API. - - API version history: - 1.0 - Initial version. - - ''' - - BASE_RPC_API_VERSION = '1.0' - - def __init__(self, topic): - super(AgentNotifierApi, self).__init__( - topic=topic, default_version=self.BASE_RPC_API_VERSION) - self.topic_network_delete = topics.get_topic_name(topic, - topics.NETWORK, - topics.DELETE) - self.topic_port_update = topics.get_topic_name(topic, - topics.PORT, - topics.UPDATE) - self.topic_port_delete = topics.get_topic_name(topic, - topics.PORT, - topics.DELETE) - self.topic_tunnel_update = topics.get_topic_name(topic, - constants.TUNNEL, - topics.UPDATE) - - def network_delete(self, context, network_id): - self.fanout_cast(context, - self.make_msg('network_delete', - network_id=network_id), - topic=self.topic_network_delete) - - def port_update(self, context, port, network_type, segmentation_id, - physical_network): - self.fanout_cast(context, - self.make_msg('port_update', - port=port, - network_type=network_type, - segmentation_id=segmentation_id, - physical_network=physical_network), - topic=self.topic_port_update) - - def port_delete(self, context, port_id): - self.fanout_cast(context, - self.make_msg('port_delete', - port_id=port_id), - topic=self.topic_port_delete) - - def tunnel_update(self, context, tunnel_ip, tunnel_id): - self.fanout_cast(context, - self.make_msg('tunnel_update', - tunnel_ip=tunnel_ip, - tunnel_id=tunnel_id), - topic=self.topic_tunnel_update) diff --git a/neutron/plugins/hyperv/common/__init__.py b/neutron/plugins/hyperv/common/__init__.py deleted file mode 100644 index 7ef4e09fa..000000000 --- a/neutron/plugins/hyperv/common/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cloudbase Solutions SRL -# 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. diff --git a/neutron/plugins/hyperv/common/constants.py b/neutron/plugins/hyperv/common/constants.py deleted file mode 100644 index b36d9b559..000000000 --- a/neutron/plugins/hyperv/common/constants.py +++ /dev/null @@ -1,23 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cloudbase Solutions SRL -# 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: Alessandro Pilotti, Cloudbase Solutions Srl - -# Topic for tunnel notifications between the plugin and agent -TUNNEL = 'tunnel' - -# Special vlan_id value in ovs_vlan_allocations table indicating flat network -FLAT_VLAN_ID = -1 diff --git a/neutron/plugins/hyperv/db.py b/neutron/plugins/hyperv/db.py deleted file mode 100644 index 159275a85..000000000 --- a/neutron/plugins/hyperv/db.py +++ /dev/null @@ -1,219 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cloudbase Solutions SRL -# 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: Alessandro Pilotti, Cloudbase Solutions Srl - -from six import moves -from sqlalchemy.orm import exc - -from neutron.common import exceptions as n_exc -import neutron.db.api as db_api -from neutron.db import models_v2 -from neutron.openstack.common import log as logging -from neutron.plugins.hyperv.common import constants -from neutron.plugins.hyperv import model as hyperv_model - -LOG = logging.getLogger(__name__) - - -class HyperVPluginDB(object): - def initialize(self): - db_api.configure_db() - - def reserve_vlan(self, session): - with session.begin(subtransactions=True): - alloc_q = session.query(hyperv_model.VlanAllocation) - alloc_q = alloc_q.filter_by(allocated=False) - alloc = alloc_q.first() - if alloc: - LOG.debug(_("Reserving vlan %(vlan_id)s on physical network " - "%(physical_network)s from pool"), - {'vlan_id': alloc.vlan_id, - 'physical_network': alloc.physical_network}) - alloc.allocated = True - return (alloc.physical_network, alloc.vlan_id) - raise n_exc.NoNetworkAvailable() - - def reserve_flat_net(self, session): - with session.begin(subtransactions=True): - alloc_q = session.query(hyperv_model.VlanAllocation) - alloc_q = alloc_q.filter_by(allocated=False, - vlan_id=constants.FLAT_VLAN_ID) - alloc = alloc_q.first() - if alloc: - LOG.debug(_("Reserving flat physical network " - "%(physical_network)s from pool"), - {'physical_network': alloc.physical_network}) - alloc.allocated = True - return alloc.physical_network - raise n_exc.NoNetworkAvailable() - - def reserve_specific_vlan(self, session, physical_network, vlan_id): - with session.begin(subtransactions=True): - try: - alloc_q = session.query(hyperv_model.VlanAllocation) - alloc_q = alloc_q.filter_by( - physical_network=physical_network, - vlan_id=vlan_id) - alloc = alloc_q.one() - if alloc.allocated: - if vlan_id == constants.FLAT_VLAN_ID: - raise n_exc.FlatNetworkInUse( - physical_network=physical_network) - else: - raise n_exc.VlanIdInUse( - vlan_id=vlan_id, - physical_network=physical_network) - LOG.debug(_("Reserving specific vlan %(vlan_id)s on physical " - "network %(physical_network)s from pool"), - {'vlan_id': vlan_id, - 'physical_network': physical_network}) - alloc.allocated = True - except exc.NoResultFound: - raise n_exc.NoNetworkAvailable() - - def reserve_specific_flat_net(self, session, physical_network): - return self.reserve_specific_vlan(session, physical_network, - constants.FLAT_VLAN_ID) - - def add_network_binding(self, session, network_id, network_type, - physical_network, segmentation_id): - with session.begin(subtransactions=True): - binding = hyperv_model.NetworkBinding( - network_id, network_type, - physical_network, - segmentation_id) - session.add(binding) - - def get_port(self, port_id): - session = db_api.get_session() - try: - port = session.query(models_v2.Port).filter_by(id=port_id).one() - except exc.NoResultFound: - port = None - return port - - def get_network_binding(self, session, network_id): - session = session or db_api.get_session() - try: - binding_q = session.query(hyperv_model.NetworkBinding) - binding_q = binding_q.filter_by(network_id=network_id) - return binding_q.one() - except exc.NoResultFound: - return - - def set_port_status(self, port_id, status): - session = db_api.get_session() - try: - port = session.query(models_v2.Port).filter_by(id=port_id).one() - port['status'] = status - session.merge(port) - session.flush() - except exc.NoResultFound: - raise n_exc.PortNotFound(port_id=port_id) - - def release_vlan(self, session, physical_network, vlan_id): - with session.begin(subtransactions=True): - try: - alloc_q = session.query(hyperv_model.VlanAllocation) - alloc_q = alloc_q.filter_by(physical_network=physical_network, - vlan_id=vlan_id) - alloc = alloc_q.one() - alloc.allocated = False - #session.delete(alloc) - LOG.debug(_("Releasing vlan %(vlan_id)s on physical network " - "%(physical_network)s"), - {'vlan_id': vlan_id, - 'physical_network': physical_network}) - except exc.NoResultFound: - LOG.warning(_("vlan_id %(vlan_id)s on physical network " - "%(physical_network)s not found"), - {'vlan_id': vlan_id, - 'physical_network': physical_network}) - - def _add_missing_allocatable_vlans(self, session, vlan_ids, - physical_network): - for vlan_id in sorted(vlan_ids): - alloc = hyperv_model.VlanAllocation( - physical_network, vlan_id) - session.add(alloc) - - def _remove_non_allocatable_vlans(self, session, - physical_network, - vlan_ids, - allocations): - if physical_network in allocations: - for alloc in allocations[physical_network]: - try: - # see if vlan is allocatable - vlan_ids.remove(alloc.vlan_id) - except KeyError: - # it's not allocatable, so check if its allocated - if not alloc.allocated: - # it's not, so remove it from table - LOG.debug(_( - "Removing vlan %(vlan_id)s on " - "physical network " - "%(physical_network)s from pool"), - {'vlan_id': alloc.vlan_id, - 'physical_network': physical_network}) - session.delete(alloc) - del allocations[physical_network] - - def _remove_unconfigured_vlans(self, session, allocations): - for allocs in allocations.itervalues(): - for alloc in allocs: - if not alloc.allocated: - LOG.debug(_("Removing vlan %(vlan_id)s on physical " - "network %(physical_network)s from pool"), - {'vlan_id': alloc.vlan_id, - 'physical_network': alloc.physical_network}) - session.delete(alloc) - - def sync_vlan_allocations(self, network_vlan_ranges): - """Synchronize vlan_allocations table with configured VLAN ranges.""" - - session = db_api.get_session() - with session.begin(): - # get existing allocations for all physical networks - allocations = dict() - allocs_q = session.query(hyperv_model.VlanAllocation) - for alloc in allocs_q: - allocations.setdefault(alloc.physical_network, - set()).add(alloc) - - # process vlan ranges for each configured physical network - for physical_network, vlan_ranges in network_vlan_ranges.items(): - # determine current configured allocatable vlans for this - # physical network - vlan_ids = set() - for vlan_range in vlan_ranges: - vlan_ids |= set(moves.xrange(vlan_range[0], - vlan_range[1] + 1)) - - # remove from table unallocated vlans not currently allocatable - self._remove_non_allocatable_vlans(session, - physical_network, - vlan_ids, - allocations) - - # add missing allocatable vlans to table - self._add_missing_allocatable_vlans(session, vlan_ids, - physical_network) - - # remove from table unallocated vlans for any unconfigured physical - # networks - self._remove_unconfigured_vlans(session, allocations) diff --git a/neutron/plugins/hyperv/hyperv_neutron_plugin.py b/neutron/plugins/hyperv/hyperv_neutron_plugin.py deleted file mode 100644 index 4307e5133..000000000 --- a/neutron/plugins/hyperv/hyperv_neutron_plugin.py +++ /dev/null @@ -1,333 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cloudbase Solutions SRL -# 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: Alessandro Pilotti, Cloudbase Solutions Srl - -from oslo.config import cfg - -from neutron.api.v2 import attributes -from neutron.common import exceptions as n_exc -from neutron.common import rpc_compat -from neutron.common import topics -from neutron.db import agents_db -from neutron.db import db_base_plugin_v2 -from neutron.db import external_net_db -from neutron.db import l3_gwmode_db -from neutron.db import portbindings_base -from neutron.db import quota_db # noqa -from neutron.extensions import portbindings -from neutron.extensions import providernet as provider -from neutron.openstack.common import log as logging -from neutron.plugins.common import constants as svc_constants -from neutron.plugins.common import utils as plugin_utils -from neutron.plugins.hyperv import agent_notifier_api -from neutron.plugins.hyperv.common import constants -from neutron.plugins.hyperv import db as hyperv_db -from neutron.plugins.hyperv import rpc_callbacks - - -DEFAULT_VLAN_RANGES = [] - -hyperv_opts = [ - cfg.StrOpt('tenant_network_type', default='local', - help=_("Network type for tenant networks " - "(local, flat, vlan or none)")), - cfg.ListOpt('network_vlan_ranges', - default=DEFAULT_VLAN_RANGES, - help=_("List of :: " - "or ")), -] - -cfg.CONF.register_opts(hyperv_opts, "HYPERV") - -LOG = logging.getLogger(__name__) - - -class BaseNetworkProvider(object): - def __init__(self): - self._db = hyperv_db.HyperVPluginDB() - - def create_network(self, session, attrs): - pass - - def delete_network(self, session, binding): - pass - - def extend_network_dict(self, network, binding): - pass - - -class LocalNetworkProvider(BaseNetworkProvider): - def create_network(self, session, attrs): - network_type = attrs.get(provider.NETWORK_TYPE) - segmentation_id = attrs.get(provider.SEGMENTATION_ID) - if attributes.is_attr_set(segmentation_id): - msg = _("segmentation_id specified " - "for %s network") % network_type - raise n_exc.InvalidInput(error_message=msg) - attrs[provider.SEGMENTATION_ID] = None - - physical_network = attrs.get(provider.PHYSICAL_NETWORK) - if attributes.is_attr_set(physical_network): - msg = _("physical_network specified " - "for %s network") % network_type - raise n_exc.InvalidInput(error_message=msg) - attrs[provider.PHYSICAL_NETWORK] = None - - def extend_network_dict(self, network, binding): - network[provider.PHYSICAL_NETWORK] = None - network[provider.SEGMENTATION_ID] = None - - -class FlatNetworkProvider(BaseNetworkProvider): - def create_network(self, session, attrs): - network_type = attrs.get(provider.NETWORK_TYPE) - segmentation_id = attrs.get(provider.SEGMENTATION_ID) - if attributes.is_attr_set(segmentation_id): - msg = _("segmentation_id specified " - "for %s network") % network_type - raise n_exc.InvalidInput(error_message=msg) - segmentation_id = constants.FLAT_VLAN_ID - attrs[provider.SEGMENTATION_ID] = segmentation_id - - physical_network = attrs.get(provider.PHYSICAL_NETWORK) - if not attributes.is_attr_set(physical_network): - physical_network = self._db.reserve_flat_net(session) - attrs[provider.PHYSICAL_NETWORK] = physical_network - else: - self._db.reserve_specific_flat_net(session, physical_network) - - def delete_network(self, session, binding): - self._db.release_vlan(session, binding.physical_network, - constants.FLAT_VLAN_ID) - - def extend_network_dict(self, network, binding): - network[provider.PHYSICAL_NETWORK] = binding.physical_network - - -class VlanNetworkProvider(BaseNetworkProvider): - def create_network(self, session, attrs): - segmentation_id = attrs.get(provider.SEGMENTATION_ID) - if attributes.is_attr_set(segmentation_id): - physical_network = attrs.get(provider.PHYSICAL_NETWORK) - if not attributes.is_attr_set(physical_network): - msg = _("physical_network not provided") - raise n_exc.InvalidInput(error_message=msg) - self._db.reserve_specific_vlan(session, physical_network, - segmentation_id) - else: - (physical_network, - segmentation_id) = self._db.reserve_vlan(session) - attrs[provider.SEGMENTATION_ID] = segmentation_id - attrs[provider.PHYSICAL_NETWORK] = physical_network - - def delete_network(self, session, binding): - self._db.release_vlan( - session, binding.physical_network, - binding.segmentation_id) - - def extend_network_dict(self, network, binding): - network[provider.PHYSICAL_NETWORK] = binding.physical_network - network[provider.SEGMENTATION_ID] = binding.segmentation_id - - -class HyperVNeutronPlugin(agents_db.AgentDbMixin, - db_base_plugin_v2.NeutronDbPluginV2, - external_net_db.External_net_db_mixin, - l3_gwmode_db.L3_NAT_db_mixin, - portbindings_base.PortBindingBaseMixin): - - # This attribute specifies whether the plugin supports or not - # bulk operations. Name mangling is used in order to ensure it - # is qualified by class - __native_bulk_support = True - supported_extension_aliases = ["provider", "external-net", "router", - "agent", "ext-gw-mode", "binding", "quotas"] - - def __init__(self, configfile=None): - self._db = hyperv_db.HyperVPluginDB() - self._db.initialize() - self.base_binding_dict = { - portbindings.VIF_TYPE: portbindings.VIF_TYPE_HYPERV} - portbindings_base.register_port_dict_function() - self._set_tenant_network_type() - - self._parse_network_vlan_ranges() - self._create_network_providers_map() - self._db.sync_vlan_allocations(self._network_vlan_ranges) - - self._setup_rpc() - - def _set_tenant_network_type(self): - tenant_network_type = cfg.CONF.HYPERV.tenant_network_type - if tenant_network_type not in [svc_constants.TYPE_LOCAL, - svc_constants.TYPE_FLAT, - svc_constants.TYPE_VLAN, - svc_constants.TYPE_NONE]: - msg = _( - "Invalid tenant_network_type: %s. " - "Agent terminated!") % tenant_network_type - raise n_exc.InvalidInput(error_message=msg) - self._tenant_network_type = tenant_network_type - - def _setup_rpc(self): - # RPC support - self.service_topics = {svc_constants.CORE: topics.PLUGIN, - svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN} - self.conn = rpc_compat.create_connection(new=True) - self.notifier = agent_notifier_api.AgentNotifierApi( - topics.AGENT) - self.endpoints = [rpc_callbacks.HyperVRpcCallbacks(self.notifier), - agents_db.AgentExtRpcCallback()] - for svc_topic in self.service_topics.values(): - self.conn.create_consumer(svc_topic, self.endpoints, fanout=False) - # Consume from all consumers in threads - self.conn.consume_in_threads() - - def _parse_network_vlan_ranges(self): - self._network_vlan_ranges = plugin_utils.parse_network_vlan_ranges( - cfg.CONF.HYPERV.network_vlan_ranges) - LOG.info(_("Network VLAN ranges: %s"), self._network_vlan_ranges) - - def _check_vlan_id_in_range(self, physical_network, vlan_id): - for r in self._network_vlan_ranges[physical_network]: - if vlan_id >= r[0] and vlan_id <= r[1]: - return True - return False - - def _create_network_providers_map(self): - self._network_providers_map = { - svc_constants.TYPE_LOCAL: LocalNetworkProvider(), - svc_constants.TYPE_FLAT: FlatNetworkProvider(), - svc_constants.TYPE_VLAN: VlanNetworkProvider() - } - - def _process_provider_create(self, context, session, attrs): - network_type = attrs.get(provider.NETWORK_TYPE) - network_type_set = attributes.is_attr_set(network_type) - if not network_type_set: - if self._tenant_network_type == svc_constants.TYPE_NONE: - raise n_exc.TenantNetworksDisabled() - network_type = self._tenant_network_type - attrs[provider.NETWORK_TYPE] = network_type - - if network_type not in self._network_providers_map: - msg = _("Network type %s not supported") % network_type - raise n_exc.InvalidInput(error_message=msg) - p = self._network_providers_map[network_type] - # Provider specific network creation - p.create_network(session, attrs) - - def create_network(self, context, network): - session = context.session - with session.begin(subtransactions=True): - network_attrs = network['network'] - self._process_provider_create(context, session, network_attrs) - - net = super(HyperVNeutronPlugin, self).create_network( - context, network) - - network_type = network_attrs[provider.NETWORK_TYPE] - physical_network = network_attrs[provider.PHYSICAL_NETWORK] - segmentation_id = network_attrs[provider.SEGMENTATION_ID] - - self._db.add_network_binding( - session, net['id'], network_type, - physical_network, segmentation_id) - - self._process_l3_create(context, net, network['network']) - self._extend_network_dict_provider(context, net) - - LOG.debug(_("Created network: %s"), net['id']) - return net - - def _extend_network_dict_provider(self, context, network): - binding = self._db.get_network_binding( - context.session, network['id']) - network[provider.NETWORK_TYPE] = binding.network_type - p = self._network_providers_map[binding.network_type] - p.extend_network_dict(network, binding) - - def update_network(self, context, id, network): - provider._raise_if_updates_provider_attributes(network['network']) - - session = context.session - with session.begin(subtransactions=True): - net = super(HyperVNeutronPlugin, self).update_network(context, id, - network) - self._process_l3_update(context, net, network['network']) - self._extend_network_dict_provider(context, net) - return net - - def delete_network(self, context, id): - session = context.session - with session.begin(subtransactions=True): - binding = self._db.get_network_binding(session, id) - self._process_l3_delete(context, id) - super(HyperVNeutronPlugin, self).delete_network(context, id) - p = self._network_providers_map[binding.network_type] - p.delete_network(session, binding) - # the network_binding record is deleted via cascade from - # the network record, so explicit removal is not necessary - self.notifier.network_delete(context, id) - - def get_network(self, context, id, fields=None): - net = super(HyperVNeutronPlugin, self).get_network(context, id, None) - self._extend_network_dict_provider(context, net) - return self._fields(net, fields) - - def get_networks(self, context, filters=None, fields=None): - nets = super(HyperVNeutronPlugin, self).get_networks( - context, filters, None) - for net in nets: - self._extend_network_dict_provider(context, net) - - return [self._fields(net, fields) for net in nets] - - def create_port(self, context, port): - port_data = port['port'] - port = super(HyperVNeutronPlugin, self).create_port(context, port) - self._process_portbindings_create_and_update(context, - port_data, - port) - return port - - def update_port(self, context, id, port): - original_port = super(HyperVNeutronPlugin, self).get_port( - context, id) - port_data = port['port'] - port = super(HyperVNeutronPlugin, self).update_port(context, id, port) - self._process_portbindings_create_and_update(context, - port_data, - port) - if original_port['admin_state_up'] != port['admin_state_up']: - binding = self._db.get_network_binding( - None, port['network_id']) - self.notifier.port_update(context, port, - binding.network_type, - binding.segmentation_id, - binding.physical_network) - return port - - def delete_port(self, context, id, l3_port_check=True): - # if needed, check to see if this is a port owned by - # and l3-router. If so, we should prevent deletion. - if l3_port_check: - self.prevent_l3_port_deletion(context, id) - self.disassociate_floatingips(context, id) - - super(HyperVNeutronPlugin, self).delete_port(context, id) - self.notifier.port_delete(context, id) diff --git a/neutron/plugins/hyperv/model.py b/neutron/plugins/hyperv/model.py deleted file mode 100644 index 808d2e591..000000000 --- a/neutron/plugins/hyperv/model.py +++ /dev/null @@ -1,55 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cloudbase Solutions SRL -# 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: Alessandro Pilotti, Cloudbase Solutions Srl - -from sqlalchemy import Boolean, Column, ForeignKey, Integer, String - -from neutron.db import model_base - - -class VlanAllocation(model_base.BASEV2): - """Represents allocation state of vlan_id on physical network.""" - __tablename__ = 'hyperv_vlan_allocations' - - physical_network = Column(String(64), nullable=False, primary_key=True) - vlan_id = Column(Integer, nullable=False, primary_key=True, - autoincrement=False) - allocated = Column(Boolean, nullable=False) - - def __init__(self, physical_network, vlan_id): - self.physical_network = physical_network - self.vlan_id = vlan_id - self.allocated = False - - -class NetworkBinding(model_base.BASEV2): - """Represents binding of virtual network to physical realization.""" - __tablename__ = 'hyperv_network_bindings' - - network_id = Column(String(36), - ForeignKey('networks.id', ondelete="CASCADE"), - primary_key=True) - network_type = Column(String(32), nullable=False) - physical_network = Column(String(64)) - segmentation_id = Column(Integer) - - def __init__(self, network_id, network_type, physical_network, - segmentation_id): - self.network_id = network_id - self.network_type = network_type - self.physical_network = physical_network - self.segmentation_id = segmentation_id diff --git a/neutron/plugins/hyperv/rpc_callbacks.py b/neutron/plugins/hyperv/rpc_callbacks.py deleted file mode 100644 index 874059a58..000000000 --- a/neutron/plugins/hyperv/rpc_callbacks.py +++ /dev/null @@ -1,94 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2013 Cloudbase Solutions SRL -# 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: Alessandro Pilotti, Cloudbase Solutions Srl - -from neutron.common import constants as q_const -from neutron.common import rpc_compat -from neutron.db import dhcp_rpc_base -from neutron.db import l3_rpc_base -from neutron.openstack.common import log as logging -from neutron.plugins.hyperv import db as hyperv_db - - -LOG = logging.getLogger(__name__) - - -class HyperVRpcCallbacks( - rpc_compat.RpcCallback, - dhcp_rpc_base.DhcpRpcCallbackMixin, - l3_rpc_base.L3RpcCallbackMixin): - - # Set RPC API version to 1.0 by default. - RPC_API_VERSION = '1.1' - - def __init__(self, notifier): - super(HyperVRpcCallbacks, self).__init__() - self.notifier = notifier - self._db = hyperv_db.HyperVPluginDB() - - def get_device_details(self, rpc_context, **kwargs): - """Agent requests device details.""" - agent_id = kwargs.get('agent_id') - device = kwargs.get('device') - LOG.debug(_("Device %(device)s details requested from %(agent_id)s"), - {'device': device, 'agent_id': agent_id}) - port = self._db.get_port(device) - if port: - binding = self._db.get_network_binding(None, port['network_id']) - entry = {'device': device, - 'network_id': port['network_id'], - 'port_id': port['id'], - 'admin_state_up': port['admin_state_up'], - 'network_type': binding.network_type, - 'segmentation_id': binding.segmentation_id, - 'physical_network': binding.physical_network} - # Set the port status to UP - self._db.set_port_status(port['id'], q_const.PORT_STATUS_ACTIVE) - else: - entry = {'device': device} - LOG.debug(_("%s can not be found in database"), device) - return entry - - def update_device_down(self, rpc_context, **kwargs): - """Device no longer exists on agent.""" - # TODO(garyk) - live migration and port status - agent_id = kwargs.get('agent_id') - device = kwargs.get('device') - LOG.debug(_("Device %(device)s no longer exists on %(agent_id)s"), - {'device': device, 'agent_id': agent_id}) - port = self._db.get_port(device) - if port: - entry = {'device': device, - 'exists': True} - # Set port status to DOWN - self._db.set_port_status(port['id'], q_const.PORT_STATUS_DOWN) - else: - entry = {'device': device, - 'exists': False} - LOG.debug(_("%s can not be found in database"), device) - return entry - - def tunnel_sync(self, rpc_context, **kwargs): - """Tunnel sync. - - Dummy function for ovs agent running on Linux to - work with Hyper-V plugin and agent. - """ - entry = dict() - entry['tunnels'] = {} - # Return the list of tunnels IP's to the agent - return entry diff --git a/neutron/plugins/ibm/README b/neutron/plugins/ibm/README deleted file mode 100644 index 732fd7776..000000000 --- a/neutron/plugins/ibm/README +++ /dev/null @@ -1,6 +0,0 @@ -IBM SDN-VE Neutron Plugin - -This plugin implements Neutron v2 APIs. - -For more details on how to use it please refer to the following page: -http://wiki.openstack.org/wiki/IBM-Neutron diff --git a/neutron/plugins/ibm/__init__.py b/neutron/plugins/ibm/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/neutron/plugins/ibm/agent/__init__.py b/neutron/plugins/ibm/agent/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/neutron/plugins/ibm/agent/sdnve_neutron_agent.py b/neutron/plugins/ibm/agent/sdnve_neutron_agent.py deleted file mode 100644 index e1c8d3ed7..000000000 --- a/neutron/plugins/ibm/agent/sdnve_neutron_agent.py +++ /dev/null @@ -1,270 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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: Mohammad Banikazemi, IBM Corp. - - -import socket -import sys -import time - -import eventlet -eventlet.monkey_patch() - -from oslo.config import cfg - -from neutron.agent.linux import ip_lib -from neutron.agent.linux import ovs_lib -from neutron.agent import rpc as agent_rpc -from neutron.common import config as common_config -from neutron.common import constants as n_const -from neutron.common import rpc_compat -from neutron.common import topics -from neutron.common import utils as n_utils -from neutron import context -from neutron.openstack.common import log as logging -from neutron.openstack.common import loopingcall -from neutron.plugins.ibm.common import config # noqa -from neutron.plugins.ibm.common import constants - - -LOG = logging.getLogger(__name__) - - -class SdnvePluginApi(agent_rpc.PluginApi): - - def sdnve_info(self, context, info): - return self.call(context, - self.make_msg('sdnve_info', info=info), - topic=self.topic) - - -class SdnveNeutronAgent(rpc_compat.RpcCallback): - - RPC_API_VERSION = '1.1' - - def __init__(self, integ_br, interface_mappings, - info, root_helper, polling_interval, - controller_ip, reset_br, out_of_band): - '''The agent initialization. - - Sets the following parameters and sets up the integration - bridge and physical interfaces if need be. - :param integ_br: name of the integration bridge. - :param interface_mappings: interfaces to physical networks. - :param info: local IP address of this hypervisor. - :param root_helper: utility to use when running shell cmds. - :param polling_interval: interval (secs) to poll DB. - :param controller_ip: Ip address of SDN-VE controller. - ''' - - super(SdnveNeutronAgent, self).__init__() - self.root_helper = root_helper - self.int_bridge_name = integ_br - self.controller_ip = controller_ip - self.interface_mappings = interface_mappings - self.polling_interval = polling_interval - self.info = info - self.reset_br = reset_br - self.out_of_band = out_of_band - - self.agent_state = { - 'binary': 'neutron-sdnve-agent', - 'host': cfg.CONF.host, - 'topic': n_const.L2_AGENT_TOPIC, - 'configurations': {'interface_mappings': interface_mappings, - 'reset_br': self.reset_br, - 'out_of_band': self.out_of_band, - 'controller_ip': self.controller_ip}, - 'agent_type': n_const.AGENT_TYPE_SDNVE, - 'start_flag': True} - - if self.int_bridge_name: - self.int_br = self.setup_integration_br(integ_br, reset_br, - out_of_band, - self.controller_ip) - self.setup_physical_interfaces(self.interface_mappings) - else: - self.int_br = None - - self.setup_rpc() - - def _report_state(self): - try: - self.state_rpc.report_state(self.context, - self.agent_state) - self.agent_state.pop('start_flag', None) - except Exception: - LOG.exception(_("Failed reporting state!")) - - def setup_rpc(self): - if self.int_br: - mac = self.int_br.get_local_port_mac() - self.agent_id = '%s%s' % ('sdnve', (mac.replace(":", ""))) - else: - nameaddr = socket.gethostbyname(socket.gethostname()) - self.agent_id = '%s%s' % ('sdnve_', (nameaddr.replace(".", "_"))) - - self.topic = topics.AGENT - self.plugin_rpc = SdnvePluginApi(topics.PLUGIN) - self.state_rpc = agent_rpc.PluginReportStateAPI(topics.PLUGIN) - - self.context = context.get_admin_context_without_session() - self.endpoints = [self] - consumers = [[constants.INFO, topics.UPDATE]] - - self.connection = agent_rpc.create_consumers(self.endpoints, - self.topic, - consumers) - if self.polling_interval: - heartbeat = loopingcall.FixedIntervalLoopingCall( - self._report_state) - heartbeat.start(interval=self.polling_interval) - - # Plugin calls the agents through the following - def info_update(self, context, **kwargs): - LOG.debug(_("info_update received")) - info = kwargs.get('info', {}) - new_controller = info.get('new_controller') - out_of_band = info.get('out_of_band') - if self.int_br and new_controller: - LOG.debug(_("info_update received. New controller" - "is to be set to: %s"), new_controller) - self.int_br.run_vsctl(["set-controller", - self.int_bridge_name, - "tcp:" + new_controller]) - if out_of_band: - LOG.debug(_("info_update received. New controller" - "is set to be out of band")) - self.int_br.set_db_attribute("controller", - self.int_bridge_name, - "connection-mode", - "out-of-band") - - def setup_integration_br(self, bridge_name, reset_br, out_of_band, - controller_ip=None): - '''Sets up the integration bridge. - - Create the bridge and remove all existing flows if reset_br is True. - Otherwise, creates the bridge if not already existing. - :param bridge_name: the name of the integration bridge. - :param reset_br: A boolean to rest the bridge if True. - :param out_of_band: A boolean indicating controller is out of band. - :param controller_ip: IP address to use as the bridge controller. - :returns: the integration bridge - ''' - - int_br = ovs_lib.OVSBridge(bridge_name, self.root_helper) - if reset_br: - int_br.reset_bridge() - int_br.remove_all_flows() - else: - int_br.create() - - # set the controller - if controller_ip: - int_br.run_vsctl( - ["set-controller", bridge_name, "tcp:" + controller_ip]) - if out_of_band: - int_br.set_db_attribute("controller", bridge_name, - "connection-mode", "out-of-band") - - return int_br - - def setup_physical_interfaces(self, interface_mappings): - '''Sets up the physical network interfaces. - - Link physical interfaces to the integration bridge. - :param interface_mappings: map physical net names to interface names. - ''' - - for physical_network, interface in interface_mappings.iteritems(): - LOG.info(_("Mapping physical network %(physical_network)s to " - "interface %(interface)s"), - {'physical_network': physical_network, - 'interface': interface}) - # Connect the physical interface to the bridge - if not ip_lib.device_exists(interface, self.root_helper): - LOG.error(_("Interface %(interface)s for physical network " - "%(physical_network)s does not exist. Agent " - "terminated!"), - {'physical_network': physical_network, - 'interface': interface}) - raise SystemExit(1) - self.int_br.add_port(interface) - - def sdnve_info(self): - details = self.plugin_rpc.sdnve_info( - self.context, - {'info': self.info}) - return details - - def rpc_loop(self): - - while True: - start = time.time() - LOG.debug(_("Agent in the rpc loop.")) - - # sleep till end of polling interval - elapsed = (time.time() - start) - if (elapsed < self.polling_interval): - time.sleep(self.polling_interval - elapsed) - else: - LOG.info(_("Loop iteration exceeded interval " - "(%(polling_interval)s vs. %(elapsed)s)!"), - {'polling_interval': self.polling_interval, - 'elapsed': elapsed}) - - def daemon_loop(self): - self.rpc_loop() - - -def create_agent_config_map(config): - - interface_mappings = n_utils.parse_mappings( - config.SDNVE.interface_mappings) - - controller_ips = config.SDNVE.controller_ips - LOG.info(_("Controller IPs: %s"), controller_ips) - controller_ip = controller_ips[0] - - return { - 'integ_br': config.SDNVE.integration_bridge, - 'interface_mappings': interface_mappings, - 'controller_ip': controller_ip, - 'info': config.SDNVE.info, - 'root_helper': config.SDNVE_AGENT.root_helper, - 'polling_interval': config.SDNVE_AGENT.polling_interval, - 'reset_br': config.SDNVE.reset_bridge, - 'out_of_band': config.SDNVE.out_of_band} - - -def main(): - cfg.CONF.register_opts(ip_lib.OPTS) - common_config.init(sys.argv[1:]) - common_config.setup_logging(cfg.CONF) - - try: - agent_config = create_agent_config_map(cfg.CONF) - except ValueError as e: - LOG.exception(_("%s Agent terminated!"), e) - raise SystemExit(1) - - plugin = SdnveNeutronAgent(**agent_config) - - # Start everything. - LOG.info(_("Agent initialized successfully, now running... ")) - plugin.daemon_loop() diff --git a/neutron/plugins/ibm/common/__init__.py b/neutron/plugins/ibm/common/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/neutron/plugins/ibm/common/config.py b/neutron/plugins/ibm/common/config.py deleted file mode 100644 index 68e2dbd42..000000000 --- a/neutron/plugins/ibm/common/config.py +++ /dev/null @@ -1,74 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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: Mohammad Banikazemi, IBM Corp. - - -from oslo.config import cfg - - -DEFAULT_INTERFACE_MAPPINGS = [] -DEFAULT_CONTROLLER_IPS = ['127.0.0.1'] - -sdnve_opts = [ - cfg.BoolOpt('use_fake_controller', default=False, - help=_("If set to True uses a fake controller.")), - cfg.StrOpt('base_url', default='/one/nb/v2/', - help=_("Base URL for SDN-VE controller REST API")), - cfg.ListOpt('controller_ips', default=DEFAULT_CONTROLLER_IPS, - help=_("List of IP addresses of SDN-VE controller(s)")), - cfg.StrOpt('info', default='sdnve_info_string', - help=_("SDN-VE RPC subject")), - cfg.StrOpt('port', default='8443', - help=_("SDN-VE controller port number")), - cfg.StrOpt('format', default='json', - help=_("SDN-VE request/response format")), - cfg.StrOpt('userid', default='admin', - help=_("SDN-VE administrator user id")), - cfg.StrOpt('password', default='admin', secret=True, - help=_("SDN-VE administrator password")), - cfg.StrOpt('integration_bridge', - help=_("Integration bridge to use")), - cfg.BoolOpt('reset_bridge', default=True, - help=_("Reset the integration bridge before use")), - cfg.BoolOpt('out_of_band', default=True, - help=_("Indicating if controller is out of band or not")), - cfg.ListOpt('interface_mappings', - default=DEFAULT_INTERFACE_MAPPINGS, - help=_("List of :")), - cfg.StrOpt('default_tenant_type', default='OVERLAY', - help=_("Tenant type: OVERLAY (default) or OF")), - cfg.StrOpt('overlay_signature', default='SDNVE-OVERLAY', - help=_("The string in tenant description that indicates " - "the tenant is a OVERLAY tenant")), - cfg.StrOpt('of_signature', default='SDNVE-OF', - help=_("The string in tenant description that indicates " - "the tenant is a OF tenant")), -] - -sdnve_agent_opts = [ - cfg.IntOpt('polling_interval', default=2, - help=_("Agent polling interval if necessary")), - cfg.StrOpt('root_helper', default='sudo', - help=_("Using root helper")), - cfg.BoolOpt('rpc', default=True, - help=_("Whether using rpc")), - -] - - -cfg.CONF.register_opts(sdnve_opts, "SDNVE") -cfg.CONF.register_opts(sdnve_agent_opts, "SDNVE_AGENT") diff --git a/neutron/plugins/ibm/common/constants.py b/neutron/plugins/ibm/common/constants.py deleted file mode 100644 index 3acf9baff..000000000 --- a/neutron/plugins/ibm/common/constants.py +++ /dev/null @@ -1,32 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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: Mohammad Banikazemi, IBM Corp. - - -import httplib - -# Topic for info notifications between the plugin and agent -INFO = 'info' - -TENANT_TYPE_OF = 'OF' -TENANT_TYPE_OVERLAY = 'OVERLAY' - -HTTP_ACCEPTABLE = [httplib.OK, - httplib.CREATED, - httplib.ACCEPTED, - httplib.NO_CONTENT - ] diff --git a/neutron/plugins/ibm/common/exceptions.py b/neutron/plugins/ibm/common/exceptions.py deleted file mode 100644 index d2e5e7ed8..000000000 --- a/neutron/plugins/ibm/common/exceptions.py +++ /dev/null @@ -1,28 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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: Mohammad Banikazemi, IBM Corp. - -from neutron.common import exceptions - - -class SdnveException(exceptions.NeutronException): - message = _("An unexpected error occurred in the SDN-VE Plugin. " - "Here is the error message: %(msg)s") - - -class BadInputException(exceptions.BadRequest): - message = _("The input does not contain nececessary info: %(msg)s") diff --git a/neutron/plugins/ibm/sdnve_api.py b/neutron/plugins/ibm/sdnve_api.py deleted file mode 100644 index 50e689c1c..000000000 --- a/neutron/plugins/ibm/sdnve_api.py +++ /dev/null @@ -1,388 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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: Mohammad Banikazemi, IBM Corp. - - -import httplib -import urllib - -import httplib2 -from keystoneclient.v2_0 import client as keyclient -from oslo.config import cfg - -from neutron.api.v2 import attributes -from neutron.openstack.common import log as logging -from neutron.plugins.ibm.common import config # noqa -from neutron.plugins.ibm.common import constants -from neutron import wsgi - -LOG = logging.getLogger(__name__) - -SDNVE_VERSION = '2.0' -SDNVE_ACTION_PREFIX = '/sdnve' -SDNVE_RETRIES = 0 -SDNVE_RETRIY_INTERVAL = 1 -SDNVE_TENANT_TYPE_OVERLAY = u'DOVE' -SDNVE_URL = 'https://%s:%s%s' - - -class RequestHandler(object): - '''Handles processing requests to and responses from controller.''' - - def __init__(self, controller_ips=None, port=None, ssl=None, - base_url=None, userid=None, password=None, - timeout=10, formats=None): - '''Initializes the RequestHandler for communication with controller - - Following keyword arguments are used; if not specified, default - values are used. - :param port: Username for authentication. - :param timeout: Time out for http requests. - :param userid: User id for accessing controller. - :param password: Password for accessing the controller. - :param base_url: The base url for the controller. - :param controller_ips: List of controller IP addresses. - :param formats: Supported formats. - ''' - self.port = port or cfg.CONF.SDNVE.port - self.timeout = timeout - self._s_meta = None - self.connection = None - self.httpclient = httplib2.Http( - disable_ssl_certificate_validation=True) - self.cookie = None - - userid = userid or cfg.CONF.SDNVE.userid - password = password or cfg.CONF.SDNVE.password - if (userid and password): - self.httpclient.add_credentials(userid, password) - - self.base_url = base_url or cfg.CONF.SDNVE.base_url - self.controller_ips = controller_ips or cfg.CONF.SDNVE.controller_ips - - LOG.info(_("The IP addr of available SDN-VE controllers: %s"), - self.controller_ips) - self.controller_ip = self.controller_ips[0] - LOG.info(_("The SDN-VE controller IP address: %s"), - self.controller_ip) - - self.new_controller = False - self.format = formats or cfg.CONF.SDNVE.format - - self.version = SDNVE_VERSION - self.action_prefix = SDNVE_ACTION_PREFIX - self.retries = SDNVE_RETRIES - self.retry_interval = SDNVE_RETRIY_INTERVAL - - def serialize(self, data): - '''Serializes a dictionary with a single key.''' - - if isinstance(data, dict): - return wsgi.Serializer().serialize(data, self.content_type()) - elif data: - raise TypeError(_("unable to serialize object type: '%s'") % - type(data)) - - def deserialize(self, data, status_code): - '''Deserializes an xml or json string into a dictionary.''' - - # NOTE(mb): Temporary fix for backend controller requirement - data = data.replace("router_external", "router:external") - - if status_code == httplib.NO_CONTENT: - return data - try: - deserialized_data = wsgi.Serializer( - metadata=self._s_meta).deserialize(data, self.content_type()) - deserialized_data = deserialized_data['body'] - except Exception: - deserialized_data = data - - return deserialized_data - - def content_type(self, format=None): - '''Returns the mime-type for either 'xml' or 'json'.''' - - return 'application/%s' % (format or self.format) - - def delete(self, url, body=None, headers=None, params=None): - return self.do_request("DELETE", url, body=body, - headers=headers, params=params) - - def get(self, url, body=None, headers=None, params=None): - return self.do_request("GET", url, body=body, - headers=headers, params=params) - - def post(self, url, body=None, headers=None, params=None): - return self.do_request("POST", url, body=body, - headers=headers, params=params) - - def put(self, url, body=None, headers=None, params=None): - return self.do_request("PUT", url, body=body, - headers=headers, params=params) - - def do_request(self, method, url, body=None, headers=None, - params=None, connection_type=None): - - status_code = -1 - replybody_deserialized = '' - - if body: - body = self.serialize(body) - - self.headers = headers or {'Content-Type': self.content_type()} - if self.cookie: - self.headers['cookie'] = self.cookie - - if self.controller_ip != self.controller_ips[0]: - controllers = [self.controller_ip] - else: - controllers = [] - controllers.extend(self.controller_ips) - - for controller_ip in controllers: - serverurl = SDNVE_URL % (controller_ip, self.port, self.base_url) - myurl = serverurl + url - if params and isinstance(params, dict): - myurl += '?' + urllib.urlencode(params, doseq=1) - - try: - LOG.debug(_("Sending request to SDN-VE. url: " - "%(myurl)s method: %(method)s body: " - "%(body)s header: %(header)s "), - {'myurl': myurl, 'method': method, - 'body': body, 'header': self.headers}) - resp, replybody = self.httpclient.request( - myurl, method=method, body=body, headers=self.headers) - LOG.debug(("Response recd from SDN-VE. resp: %(resp)s" - "body: %(body)s"), - {'resp': resp.status, 'body': replybody}) - status_code = resp.status - - except Exception as e: - LOG.error(_("Error: Could not reach server: %(url)s " - "Exception: %(excp)s."), - {'url': myurl, 'excp': e}) - self.cookie = None - continue - - if status_code not in constants.HTTP_ACCEPTABLE: - LOG.debug(_("Error message: %(reply)s -- Status: %(status)s"), - {'reply': replybody, 'status': status_code}) - else: - LOG.debug(_("Received response status: %s"), status_code) - - if resp.get('set-cookie'): - self.cookie = resp['set-cookie'] - replybody_deserialized = self.deserialize( - replybody, - status_code) - LOG.debug(_("Deserialized body: %s"), replybody_deserialized) - if controller_ip != self.controller_ip: - # bcast the change of controller - self.new_controller = True - self.controller_ip = controller_ip - - return (status_code, replybody_deserialized) - - return (httplib.REQUEST_TIMEOUT, 'Could not reach server(s)') - - -class Client(RequestHandler): - '''Client for SDNVE controller.''' - - def __init__(self): - '''Initialize a new SDNVE client.''' - super(Client, self).__init__() - - self.keystoneclient = KeystoneClient() - - resource_path = { - 'network': "ln/networks/", - 'subnet': "ln/subnets/", - 'port': "ln/ports/", - 'tenant': "ln/tenants/", - 'router': "ln/routers/", - 'floatingip': "ln/floatingips/", - } - - def process_request(self, body): - '''Processes requests according to requirements of controller.''' - if self.format == 'json': - body = dict( - (k.replace(':', '_'), v) for k, v in body.items() - if attributes.is_attr_set(v)) - return body - - def sdnve_list(self, resource, **params): - '''Fetches a list of resources.''' - - res = self.resource_path.get(resource, None) - if not res: - LOG.info(_("Bad resource for forming a list request")) - return 0, '' - - return self.get(res, params=params) - - def sdnve_show(self, resource, specific, **params): - '''Fetches information of a certain resource.''' - - res = self.resource_path.get(resource, None) - if not res: - LOG.info(_("Bad resource for forming a show request")) - return 0, '' - - return self.get(res + specific, params=params) - - def sdnve_create(self, resource, body): - '''Creates a new resource.''' - - res = self.resource_path.get(resource, None) - if not res: - LOG.info(_("Bad resource for forming a create request")) - return 0, '' - - body = self.process_request(body) - status, data = self.post(res, body=body) - return (status, data) - - def sdnve_update(self, resource, specific, body=None): - '''Updates a resource.''' - - res = self.resource_path.get(resource, None) - if not res: - LOG.info(_("Bad resource for forming a update request")) - return 0, '' - - body = self.process_request(body) - return self.put(res + specific, body=body) - - def sdnve_delete(self, resource, specific): - '''Deletes the specified resource.''' - - res = self.resource_path.get(resource, None) - if not res: - LOG.info(_("Bad resource for forming a delete request")) - return 0, '' - - return self.delete(res + specific) - - def _tenant_id_conversion(self, osid): - return osid - - def sdnve_get_tenant_byid(self, os_tenant_id): - sdnve_tenant_id = self._tenant_id_conversion(os_tenant_id) - resp, content = self.sdnve_show('tenant', sdnve_tenant_id) - if resp in constants.HTTP_ACCEPTABLE: - tenant_id = content.get('id') - tenant_type = content.get('network_type') - if tenant_type == SDNVE_TENANT_TYPE_OVERLAY: - tenant_type = constants.TENANT_TYPE_OVERLAY - return tenant_id, tenant_type - return None, None - - def sdnve_check_and_create_tenant(self, os_tenant_id, network_type=None): - - if not os_tenant_id: - return - tenant_id, tenant_type = self.sdnve_get_tenant_byid(os_tenant_id) - if tenant_id: - if not network_type: - return tenant_id - if tenant_type != network_type: - LOG.info(_("Non matching tenant and network types: " - "%(ttype)s %(ntype)s"), - {'ttype': tenant_type, 'ntype': network_type}) - return - return tenant_id - - # Have to create a new tenant - sdnve_tenant_id = self._tenant_id_conversion(os_tenant_id) - if not network_type: - network_type = self.keystoneclient.get_tenant_type(os_tenant_id) - if network_type == constants.TENANT_TYPE_OVERLAY: - network_type = SDNVE_TENANT_TYPE_OVERLAY - - pinn_desc = ("Created by SDN-VE Neutron Plugin, OS project name = " + - self.keystoneclient.get_tenant_name(os_tenant_id)) - - res, content = self.sdnve_create('tenant', - {'id': sdnve_tenant_id, - 'name': os_tenant_id, - 'network_type': network_type, - 'description': pinn_desc}) - if res not in constants.HTTP_ACCEPTABLE: - return - - return sdnve_tenant_id - - def sdnve_get_controller(self): - if self.new_controller: - self.new_controller = False - return self.controller_ip - - -class KeystoneClient(object): - - def __init__(self, username=None, tenant_name=None, password=None, - auth_url=None): - - keystone_conf = cfg.CONF.keystone_authtoken - keystone_auth_url = ('%s://%s:%s/v2.0/' % - (keystone_conf.auth_protocol, - keystone_conf.auth_host, - keystone_conf.auth_port)) - - username = username or keystone_conf.admin_user - tenant_name = tenant_name or keystone_conf.admin_tenant_name - password = password or keystone_conf.admin_password - auth_url = auth_url or keystone_auth_url - - self.overlay_signature = cfg.CONF.SDNVE.overlay_signature - self.of_signature = cfg.CONF.SDNVE.of_signature - self.default_tenant_type = cfg.CONF.SDNVE.default_tenant_type - - self.client = keyclient.Client(username=username, - password=password, - tenant_name=tenant_name, - auth_url=auth_url) - - def get_tenant_byid(self, id): - - try: - return self.client.tenants.get(id) - except Exception: - LOG.exception(_("Did not find tenant: %r"), id) - - def get_tenant_type(self, id): - - tenant = self.get_tenant_byid(id) - if tenant: - description = tenant.description - if description: - if (description.find(self.overlay_signature) >= 0): - return constants.TENANT_TYPE_OVERLAY - if (description.find(self.of_signature) >= 0): - return constants.TENANT_TYPE_OF - return self.default_tenant_type - - def get_tenant_name(self, id): - - tenant = self.get_tenant_byid(id) - if tenant: - return tenant.name - return 'not found' diff --git a/neutron/plugins/ibm/sdnve_api_fake.py b/neutron/plugins/ibm/sdnve_api_fake.py deleted file mode 100644 index 74cfc8386..000000000 --- a/neutron/plugins/ibm/sdnve_api_fake.py +++ /dev/null @@ -1,64 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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: Mohammad Banikazemi, IBM Corp. - -from neutron.openstack.common import log as logging -from neutron.plugins.ibm.common import constants - -LOG = logging.getLogger(__name__) - -HTTP_OK = 200 - - -class FakeClient(): - - '''Fake Client for SDNVE controller.''' - - def __init__(self, **kwargs): - LOG.info(_('Fake SDNVE controller initialized')) - - def sdnve_list(self, resource, **_params): - LOG.info(_('Fake SDNVE controller: list')) - return (HTTP_OK, None) - - def sdnve_show(self, resource, specific, **_params): - LOG.info(_('Fake SDNVE controller: show')) - return (HTTP_OK, None) - - def sdnve_create(self, resource, body): - LOG.info(_('Fake SDNVE controller: create')) - return (HTTP_OK, None) - - def sdnve_update(self, resource, specific, body=None): - LOG.info(_('Fake SDNVE controller: update')) - return (HTTP_OK, None) - - def sdnve_delete(self, resource, specific): - LOG.info(_('Fake SDNVE controller: delete')) - return (HTTP_OK, None) - - def sdnve_get_tenant_byid(self, id): - LOG.info(_('Fake SDNVE controller: get tenant by id')) - return id, constants.TENANT_TYPE_OF - - def sdnve_check_and_create_tenant(self, id, network_type=None): - LOG.info(_('Fake SDNVE controller: check and create tenant')) - return id - - def sdnve_get_controller(self): - LOG.info(_('Fake SDNVE controller: get controller')) - return None diff --git a/neutron/plugins/ibm/sdnve_neutron_plugin.py b/neutron/plugins/ibm/sdnve_neutron_plugin.py deleted file mode 100644 index cf127f001..000000000 --- a/neutron/plugins/ibm/sdnve_neutron_plugin.py +++ /dev/null @@ -1,666 +0,0 @@ -# Copyright 2014 IBM Corp. -# -# 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: Mohammad Banikazemi, IBM Corp. - - -import functools - -from oslo.config import cfg - -from neutron.common import constants as n_const -from neutron.common import exceptions as n_exc -from neutron.common import rpc_compat -from neutron.common import topics -from neutron.db import agents_db -from neutron.db import db_base_plugin_v2 -from neutron.db import external_net_db -from neutron.db import l3_gwmode_db -from neutron.db import portbindings_db -from neutron.db import quota_db # noqa -from neutron.extensions import portbindings -from neutron.openstack.common import excutils -from neutron.openstack.common import log as logging -from neutron.plugins.ibm.common import config # noqa -from neutron.plugins.ibm.common import constants -from neutron.plugins.ibm.common import exceptions as sdnve_exc -from neutron.plugins.ibm import sdnve_api as sdnve -from neutron.plugins.ibm import sdnve_api_fake as sdnve_fake - -LOG = logging.getLogger(__name__) - - -class SdnveRpcCallbacks(): - - def __init__(self, notifier): - self.notifier = notifier # used to notify the agent - - def sdnve_info(self, rpc_context, **kwargs): - '''Update new information.''' - info = kwargs.get('info') - # Notify all other listening agents - self.notifier.info_update(rpc_context, info) - return info - - -class AgentNotifierApi(rpc_compat.RpcProxy): - '''Agent side of the SDN-VE rpc API.''' - - BASE_RPC_API_VERSION = '1.0' - - def __init__(self, topic): - super(AgentNotifierApi, self).__init__( - topic=topic, default_version=self.BASE_RPC_API_VERSION) - - self.topic_info_update = topics.get_topic_name(topic, - constants.INFO, - topics.UPDATE) - - def info_update(self, context, info): - self.fanout_cast(context, - self.make_msg('info_update', - info=info), - topic=self.topic_info_update) - - -def _ha(func): - '''Supports the high availability feature of the controller.''' - - @functools.wraps(func) - def hawrapper(self, *args, **kwargs): - '''This wrapper sets the new controller if necessary - - When a controller is detected to be not responding, and a - new controller is chosen to be used in its place, this decorator - makes sure the existing integration bridges are set to point - to the new controller by calling the set_controller method. - ''' - ret_func = func(self, *args, **kwargs) - self.set_controller(args[0]) - return ret_func - return hawrapper - - -class SdnvePluginV2(db_base_plugin_v2.NeutronDbPluginV2, - external_net_db.External_net_db_mixin, - portbindings_db.PortBindingMixin, - l3_gwmode_db.L3_NAT_db_mixin, - agents_db.AgentDbMixin, - ): - - ''' - Implement the Neutron abstractions using SDN-VE SDN Controller. - ''' - - __native_bulk_support = False - __native_pagination_support = False - __native_sorting_support = False - - supported_extension_aliases = ["binding", "router", "external-net", - "agent", "quotas"] - - def __init__(self, configfile=None): - self.base_binding_dict = { - portbindings.VIF_TYPE: portbindings.VIF_TYPE_OVS, - portbindings.VIF_DETAILS: {portbindings.CAP_PORT_FILTER: False}} - - super(SdnvePluginV2, self).__init__() - self.setup_rpc() - self.sdnve_controller_select() - if self.fake_controller: - self.sdnve_client = sdnve_fake.FakeClient() - else: - self.sdnve_client = sdnve.Client() - - def sdnve_controller_select(self): - self.fake_controller = cfg.CONF.SDNVE.use_fake_controller - - def setup_rpc(self): - # RPC support - self.topic = topics.PLUGIN - self.conn = rpc_compat.create_connection(new=True) - self.notifier = AgentNotifierApi(topics.AGENT) - self.endpoints = [SdnveRpcCallbacks(self.notifier), - agents_db.AgentExtRpcCallback()] - self.conn.create_consumer(self.topic, self.endpoints, - fanout=False) - # Consume from all consumers in threads - self.conn.consume_in_threads() - - def _update_base_binding_dict(self, tenant_type): - if tenant_type == constants.TENANT_TYPE_OVERLAY: - self.base_binding_dict[ - portbindings.VIF_TYPE] = portbindings.VIF_TYPE_BRIDGE - if tenant_type == constants.TENANT_TYPE_OF: - self.base_binding_dict[ - portbindings.VIF_TYPE] = portbindings.VIF_TYPE_OVS - - def set_controller(self, context): - LOG.info(_("Set a new controller if needed.")) - new_controller = self.sdnve_client.sdnve_get_controller() - if new_controller: - self.notifier.info_update( - context, - {'new_controller': new_controller}) - LOG.info(_("Set the controller to a new controller: %s"), - new_controller) - - def _process_request(self, request, current): - new_request = dict( - (k, v) for k, v in request.items() - if v != current.get(k)) - - msg = _("Original SDN-VE HTTP request: %(orig)s; New request: %(new)s") - LOG.debug(msg, {'orig': request, 'new': new_request}) - return new_request - - # - # Network - # - - @_ha - def create_network(self, context, network): - LOG.debug(_("Create network in progress: %r"), network) - session = context.session - - tenant_id = self._get_tenant_id_for_create(context, network['network']) - # Create a new SDN-VE tenant if need be - sdnve_tenant = self.sdnve_client.sdnve_check_and_create_tenant( - tenant_id) - if sdnve_tenant is None: - raise sdnve_exc.SdnveException( - msg=_('Create net failed: no SDN-VE tenant.')) - - with session.begin(subtransactions=True): - net = super(SdnvePluginV2, self).create_network(context, network) - self._process_l3_create(context, net, network['network']) - - # Create SDN-VE network - (res, data) = self.sdnve_client.sdnve_create('network', net) - if res not in constants.HTTP_ACCEPTABLE: - super(SdnvePluginV2, self).delete_network(context, net['id']) - raise sdnve_exc.SdnveException( - msg=(_('Create net failed in SDN-VE: %s') % res)) - - LOG.debug(_("Created network: %s"), net['id']) - return net - - @_ha - def update_network(self, context, id, network): - LOG.debug(_("Update network in progress: %r"), network) - session = context.session - - processed_request = {} - with session.begin(subtransactions=True): - original_network = super(SdnvePluginV2, self).get_network( - context, id) - processed_request['network'] = self._process_request( - network['network'], original_network) - net = super(SdnvePluginV2, self).update_network( - context, id, network) - self._process_l3_update(context, net, network['network']) - - if processed_request['network']: - (res, data) = self.sdnve_client.sdnve_update( - 'network', id, processed_request['network']) - if res not in constants.HTTP_ACCEPTABLE: - net = super(SdnvePluginV2, self).update_network( - context, id, {'network': original_network}) - raise sdnve_exc.SdnveException( - msg=(_('Update net failed in SDN-VE: %s') % res)) - - return net - - @_ha - def delete_network(self, context, id): - LOG.debug(_("Delete network in progress: %s"), id) - session = context.session - - with session.begin(subtransactions=True): - self._process_l3_delete(context, id) - super(SdnvePluginV2, self).delete_network(context, id) - - (res, data) = self.sdnve_client.sdnve_delete('network', id) - if res not in constants.HTTP_ACCEPTABLE: - LOG.error( - _("Delete net failed after deleting the network in DB: %s"), - res) - - @_ha - def get_network(self, context, id, fields=None): - LOG.debug(_("Get network in progress: %s"), id) - return super(SdnvePluginV2, self).get_network(context, id, fields) - - @_ha - def get_networks(self, context, filters=None, fields=None, sorts=None, - limit=None, marker=None, page_reverse=False): - LOG.debug(_("Get networks in progress")) - return super(SdnvePluginV2, self).get_networks( - context, filters, fields, sorts, limit, marker, page_reverse) - - # - # Port - # - - @_ha - def create_port(self, context, port): - LOG.debug(_("Create port in progress: %r"), port) - session = context.session - - # Set port status as 'ACTIVE' to avoid needing the agent - port['port']['status'] = n_const.PORT_STATUS_ACTIVE - port_data = port['port'] - - with session.begin(subtransactions=True): - port = super(SdnvePluginV2, self).create_port(context, port) - if 'id' not in port: - return port - # If the tenant_id is set to '' by create_port, add the id to - # the request being sent to the controller as the controller - # requires a tenant id - tenant_id = port.get('tenant_id') - if not tenant_id: - LOG.debug(_("Create port does not have tenant id info")) - original_network = super(SdnvePluginV2, self).get_network( - context, port['network_id']) - original_tenant_id = original_network['tenant_id'] - port['tenant_id'] = original_tenant_id - LOG.debug( - _("Create port does not have tenant id info; " - "obtained is: %s"), - port['tenant_id']) - - os_tenant_id = tenant_id - id_na, tenant_type = self.sdnve_client.sdnve_get_tenant_byid( - os_tenant_id) - self._update_base_binding_dict(tenant_type) - self._process_portbindings_create_and_update(context, - port_data, port) - - # NOTE(mb): Remove this block when controller is updated - # Remove the information that the controller does not accept - sdnve_port = port.copy() - sdnve_port.pop('device_id', None) - sdnve_port.pop('device_owner', None) - - (res, data) = self.sdnve_client.sdnve_create('port', sdnve_port) - if res not in constants.HTTP_ACCEPTABLE: - super(SdnvePluginV2, self).delete_port(context, port['id']) - raise sdnve_exc.SdnveException( - msg=(_('Create port failed in SDN-VE: %s') % res)) - - LOG.debug(_("Created port: %s"), port.get('id', 'id not found')) - return port - - @_ha - def update_port(self, context, id, port): - LOG.debug(_("Update port in progress: %r"), port) - session = context.session - - processed_request = {} - with session.begin(subtransactions=True): - original_port = super(SdnvePluginV2, self).get_port( - context, id) - processed_request['port'] = self._process_request( - port['port'], original_port) - updated_port = super(SdnvePluginV2, self).update_port( - context, id, port) - - os_tenant_id = updated_port['tenant_id'] - id_na, tenant_type = self.sdnve_client.sdnve_get_tenant_byid( - os_tenant_id) - self._update_base_binding_dict(tenant_type) - self._process_portbindings_create_and_update(context, - port['port'], - updated_port) - - if processed_request['port']: - (res, data) = self.sdnve_client.sdnve_update( - 'port', id, processed_request['port']) - if res not in constants.HTTP_ACCEPTABLE: - updated_port = super(SdnvePluginV2, self).update_port( - context, id, {'port': original_port}) - raise sdnve_exc.SdnveException( - msg=(_('Update port failed in SDN-VE: %s') % res)) - - return updated_port - - @_ha - def delete_port(self, context, id, l3_port_check=True): - LOG.debug(_("Delete port in progress: %s"), id) - - # if needed, check to see if this is a port owned by - # an l3-router. If so, we should prevent deletion. - if l3_port_check: - self.prevent_l3_port_deletion(context, id) - self.disassociate_floatingips(context, id) - - super(SdnvePluginV2, self).delete_port(context, id) - - (res, data) = self.sdnve_client.sdnve_delete('port', id) - if res not in constants.HTTP_ACCEPTABLE: - LOG.error( - _("Delete port operation failed in SDN-VE " - "after deleting the port from DB: %s"), res) - - # - # Subnet - # - - @_ha - def create_subnet(self, context, subnet): - LOG.debug(_("Create subnet in progress: %r"), subnet) - new_subnet = super(SdnvePluginV2, self).create_subnet(context, subnet) - - # Note(mb): Use of null string currently required by controller - sdnve_subnet = new_subnet.copy() - if subnet.get('gateway_ip') is None: - sdnve_subnet['gateway_ip'] = 'null' - (res, data) = self.sdnve_client.sdnve_create('subnet', sdnve_subnet) - if res not in constants.HTTP_ACCEPTABLE: - super(SdnvePluginV2, self).delete_subnet(context, - new_subnet['id']) - raise sdnve_exc.SdnveException( - msg=(_('Create subnet failed in SDN-VE: %s') % res)) - - LOG.debug(_("Subnet created: %s"), new_subnet['id']) - - return new_subnet - - @_ha - def update_subnet(self, context, id, subnet): - LOG.debug(_("Update subnet in progress: %r"), subnet) - session = context.session - - processed_request = {} - with session.begin(subtransactions=True): - original_subnet = super(SdnvePluginV2, self).get_subnet( - context, id) - processed_request['subnet'] = self._process_request( - subnet['subnet'], original_subnet) - updated_subnet = super(SdnvePluginV2, self).update_subnet( - context, id, subnet) - - if processed_request['subnet']: - # Note(mb): Use of string containing null required by controller - if 'gateway_ip' in processed_request['subnet']: - if processed_request['subnet'].get('gateway_ip') is None: - processed_request['subnet']['gateway_ip'] = 'null' - (res, data) = self.sdnve_client.sdnve_update( - 'subnet', id, processed_request['subnet']) - if res not in constants.HTTP_ACCEPTABLE: - for key in subnet['subnet'].keys(): - subnet['subnet'][key] = original_subnet[key] - super(SdnvePluginV2, self).update_subnet( - context, id, subnet) - raise sdnve_exc.SdnveException( - msg=(_('Update subnet failed in SDN-VE: %s') % res)) - - return updated_subnet - - @_ha - def delete_subnet(self, context, id): - LOG.debug(_("Delete subnet in progress: %s"), id) - super(SdnvePluginV2, self).delete_subnet(context, id) - - (res, data) = self.sdnve_client.sdnve_delete('subnet', id) - if res not in constants.HTTP_ACCEPTABLE: - LOG.error(_("Delete subnet operation failed in SDN-VE after " - "deleting the subnet from DB: %s"), res) - - # - # Router - # - - @_ha - def create_router(self, context, router): - LOG.debug(_("Create router in progress: %r"), router) - - if router['router']['admin_state_up'] is False: - LOG.warning(_('Ignoring admin_state_up=False for router=%r. ' - 'Overriding with True'), router) - router['router']['admin_state_up'] = True - - tenant_id = self._get_tenant_id_for_create(context, router['router']) - # Create a new SDN-VE tenant if need be - sdnve_tenant = self.sdnve_client.sdnve_check_and_create_tenant( - tenant_id) - if sdnve_tenant is None: - raise sdnve_exc.SdnveException( - msg=_('Create router failed: no SDN-VE tenant.')) - - new_router = super(SdnvePluginV2, self).create_router(context, router) - # Create SDN-VE router - (res, data) = self.sdnve_client.sdnve_create('router', new_router) - if res not in constants.HTTP_ACCEPTABLE: - super(SdnvePluginV2, self).delete_router(context, new_router['id']) - raise sdnve_exc.SdnveException( - msg=(_('Create router failed in SDN-VE: %s') % res)) - - LOG.debug(_("Router created: %r"), new_router) - return new_router - - @_ha - def update_router(self, context, id, router): - LOG.debug(_("Update router in progress: id=%(id)s " - "router=%(router)r"), - {'id': id, 'router': router}) - session = context.session - - processed_request = {} - if not router['router'].get('admin_state_up', True): - raise n_exc.NotImplementedError(_('admin_state_up=False ' - 'routers are not ' - 'supported.')) - - with session.begin(subtransactions=True): - original_router = super(SdnvePluginV2, self).get_router( - context, id) - processed_request['router'] = self._process_request( - router['router'], original_router) - updated_router = super(SdnvePluginV2, self).update_router( - context, id, router) - - if processed_request['router']: - egw = processed_request['router'].get('external_gateway_info') - # Check for existing empty set (different from None) in request - if egw == {}: - processed_request['router'][ - 'external_gateway_info'] = {'network_id': 'null'} - (res, data) = self.sdnve_client.sdnve_update( - 'router', id, processed_request['router']) - if res not in constants.HTTP_ACCEPTABLE: - super(SdnvePluginV2, self).update_router( - context, id, {'router': original_router}) - raise sdnve_exc.SdnveException( - msg=(_('Update router failed in SDN-VE: %s') % res)) - - return updated_router - - @_ha - def delete_router(self, context, id): - LOG.debug(_("Delete router in progress: %s"), id) - - super(SdnvePluginV2, self).delete_router(context, id) - - (res, data) = self.sdnve_client.sdnve_delete('router', id) - if res not in constants.HTTP_ACCEPTABLE: - LOG.error( - _("Delete router operation failed in SDN-VE after " - "deleting the router in DB: %s"), res) - - @_ha - def add_router_interface(self, context, router_id, interface_info): - LOG.debug(_("Add router interface in progress: " - "router_id=%(router_id)s " - "interface_info=%(interface_info)r"), - {'router_id': router_id, 'interface_info': interface_info}) - - new_interface = super(SdnvePluginV2, self).add_router_interface( - context, router_id, interface_info) - LOG.debug( - _("SdnvePluginV2.add_router_interface called. Port info: %s"), - new_interface) - request_info = interface_info.copy() - request_info['port_id'] = new_interface['port_id'] - # Add the subnet_id to the request sent to the controller - if 'subnet_id' not in interface_info: - request_info['subnet_id'] = new_interface['subnet_id'] - - (res, data) = self.sdnve_client.sdnve_update( - 'router', router_id + '/add_router_interface', request_info) - if res not in constants.HTTP_ACCEPTABLE: - super(SdnvePluginV2, self).remove_router_interface( - context, router_id, interface_info) - raise sdnve_exc.SdnveException( - msg=(_('Update router-add-interface failed in SDN-VE: %s') % - res)) - - LOG.debug(_("Added router interface: %r"), new_interface) - return new_interface - - def _add_router_interface_only(self, context, router_id, interface_info): - LOG.debug(_("Add router interface only called: " - "router_id=%(router_id)s " - "interface_info=%(interface_info)r"), - {'router_id': router_id, 'interface_info': interface_info}) - - port_id = interface_info.get('port_id') - if port_id: - (res, data) = self.sdnve_client.sdnve_update( - 'router', router_id + '/add_router_interface', interface_info) - if res not in constants.HTTP_ACCEPTABLE: - LOG.error(_("SdnvePluginV2._add_router_interface_only: " - "failed to add the interface in the roll back." - " of a remove_router_interface operation")) - - @_ha - def remove_router_interface(self, context, router_id, interface_info): - LOG.debug(_("Remove router interface in progress: " - "router_id=%(router_id)s " - "interface_info=%(interface_info)r"), - {'router_id': router_id, 'interface_info': interface_info}) - - subnet_id = interface_info.get('subnet_id') - port_id = interface_info.get('port_id') - if not subnet_id: - if not port_id: - raise sdnve_exc.BadInputException(msg=_('No port ID')) - myport = super(SdnvePluginV2, self).get_port(context, port_id) - LOG.debug(_("SdnvePluginV2.remove_router_interface port: %s"), - myport) - myfixed_ips = myport.get('fixed_ips') - if not myfixed_ips: - raise sdnve_exc.BadInputException(msg=_('No fixed IP')) - subnet_id = myfixed_ips[0].get('subnet_id') - if subnet_id: - interface_info['subnet_id'] = subnet_id - LOG.debug( - _("SdnvePluginV2.remove_router_interface subnet_id: %s"), - subnet_id) - else: - if not port_id: - # The backend requires port id info in the request - subnet = super(SdnvePluginV2, self).get_subnet(context, - subnet_id) - df = {'device_id': [router_id], - 'device_owner': [n_const.DEVICE_OWNER_ROUTER_INTF], - 'network_id': [subnet['network_id']]} - ports = self.get_ports(context, filters=df) - if ports: - pid = ports[0]['id'] - interface_info['port_id'] = pid - msg = ("SdnvePluginV2.remove_router_interface " - "subnet_id: %(sid)s port_id: %(pid)s") - LOG.debug(msg, {'sid': subnet_id, 'pid': pid}) - - (res, data) = self.sdnve_client.sdnve_update( - 'router', router_id + '/remove_router_interface', interface_info) - - if res not in constants.HTTP_ACCEPTABLE: - raise sdnve_exc.SdnveException( - msg=(_('Update router-remove-interface failed SDN-VE: %s') % - res)) - - session = context.session - with session.begin(subtransactions=True): - try: - info = super(SdnvePluginV2, self).remove_router_interface( - context, router_id, interface_info) - except Exception: - with excutils.save_and_reraise_exception(): - self._add_router_interface_only(context, - router_id, interface_info) - - return info - - # - # Floating Ip - # - - @_ha - def create_floatingip(self, context, floatingip): - LOG.debug(_("Create floatingip in progress: %r"), - floatingip) - new_floatingip = super(SdnvePluginV2, self).create_floatingip( - context, floatingip) - - (res, data) = self.sdnve_client.sdnve_create( - 'floatingip', {'floatingip': new_floatingip}) - if res not in constants.HTTP_ACCEPTABLE: - super(SdnvePluginV2, self).delete_floatingip( - context, new_floatingip['id']) - raise sdnve_exc.SdnveException( - msg=(_('Creating floating ip operation failed ' - 'in SDN-VE controller: %s') % res)) - - LOG.debug(_("Created floatingip : %r"), new_floatingip) - return new_floatingip - - @_ha - def update_floatingip(self, context, id, floatingip): - LOG.debug(_("Update floatingip in progress: %r"), floatingip) - session = context.session - - processed_request = {} - with session.begin(subtransactions=True): - original_floatingip = super( - SdnvePluginV2, self).get_floatingip(context, id) - processed_request['floatingip'] = self._process_request( - floatingip['floatingip'], original_floatingip) - updated_floatingip = super( - SdnvePluginV2, self).update_floatingip(context, id, floatingip) - - if processed_request['floatingip']: - (res, data) = self.sdnve_client.sdnve_update( - 'floatingip', id, - {'floatingip': processed_request['floatingip']}) - if res not in constants.HTTP_ACCEPTABLE: - super(SdnvePluginV2, self).update_floatingip( - context, id, {'floatingip': original_floatingip}) - raise sdnve_exc.SdnveException( - msg=(_('Update floating ip failed in SDN-VE: %s') % res)) - - return updated_floatingip - - @_ha - def delete_floatingip(self, context, id): - LOG.debug(_("Delete floatingip in progress: %s"), id) - super(SdnvePluginV2, self).delete_floatingip(context, id) - - (res, data) = self.sdnve_client.sdnve_delete('floatingip', id) - if res not in constants.HTTP_ACCEPTABLE: - LOG.error(_("Delete floatingip failed in SDN-VE: %s"), res) diff --git a/neutron/plugins/linuxbridge/README b/neutron/plugins/linuxbridge/README deleted file mode 100644 index b7601205f..000000000 --- a/neutron/plugins/linuxbridge/README +++ /dev/null @@ -1,169 +0,0 @@ -# -- Background - -The Neutron Linux Bridge plugin is a plugin that allows you to manage -connectivity between VMs on hosts that are capable of running a Linux Bridge. - -The Neutron Linux Bridge plugin consists of three components: - -1) The plugin itself: The plugin uses a database backend (mysql for - now) to store configuration and mappings that are used by the - agent. The mysql server runs on a central server (often the same - host as nova itself). - -2) The neutron service host which will be running neutron. This can - be run on the server running nova. - -3) An agent which runs on the host and communicates with the host operating - system. The agent gathers the configuration and mappings from - the mysql database running on the neutron host. - -The sections below describe how to configure and run the neutron -service with the Linux Bridge plugin. - -# -- Python library dependencies - - Make sure you have the following package(s) installedi on neutron server - host as well as any hosts which run the agent: - python-configobj - bridge-utils - python-mysqldb - sqlite3 - -# -- Nova configuration (controller node) - -1) Ensure that the neutron network manager is configured in the - nova.conf on the node that will be running nova-network. - -network_manager=nova.network.neutron.manager.NeutronManager - -# -- Nova configuration (compute node(s)) - -1) Configure the vif driver, and libvirt/vif type - -connection_type=libvirt -libvirt_type=qemu -libvirt_vif_type=ethernet -libvirt_vif_driver=nova.virt.libvirt.vif.NeutronLinuxBridgeVIFDriver -linuxnet_interface_driver=nova.network.linux_net.NeutronLinuxBridgeInterfaceDriver - -2) If you want a DHCP server to be run for the VMs to acquire IPs, - add the following flag to your nova.conf file: - -neutron_use_dhcp=true - -(Note: For more details on how to work with Neutron using Nova, i.e. how to create networks and such, - please refer to the top level Neutron README which points to the relevant documentation.) - -# -- Neutron configuration - -Make the Linux Bridge plugin the current neutron plugin - -- edit neutron.conf and change the core_plugin - -core_plugin = neutron.plugins.linuxbridge.lb_neutron_plugin.LinuxBridgePluginV2 - -# -- Database config. - -(Note: The plugin ships with a default SQLite in-memory database configuration, - and can be used to run tests without performing the suggested DB config below.) - -The Linux Bridge neutron plugin requires access to a mysql database in order -to store configuration and mappings that will be used by the agent. Here is -how to set up the database on the host that you will be running the neutron -service on. - -MySQL should be installed on the host, and all plugins and clients -must be configured with access to the database. - -To prep mysql, run: - -$ mysql -u root -p -e "create database neutron_linux_bridge" - -# log in to mysql service -$ mysql -u root -p -# The Linux Bridge Neutron agent running on each compute node must be able to -# make a mysql connection back to the main database server. -mysql> GRANT USAGE ON *.* to root@'yourremotehost' IDENTIFIED BY 'newpassword'; -# force update of authorization changes -mysql> FLUSH PRIVILEGES; - -(Note: If the remote connection fails to MySQL, you might need to add the IP address, - and/or fully-qualified hostname, and/or unqualified hostname in the above GRANT sql - command. Also, you might need to specify "ALL" instead of "USAGE".) - -# -- Plugin configuration - -- Edit the configuration file: - etc/neutron/plugins/linuxbridge/linuxbridge_conf.ini - Make sure it matches your mysql configuration. This file must be updated - with the addresses and credentials to access the database. - - Note: debug and logging information should be updated in etc/neutron.conf - - Note: When running the tests, set the connection type to sqlite, and when - actually running the server set it to mysql. At any given time, only one - of these should be active in the conf file (you can comment out the other). - -- On the neutron server, network_vlan_ranges must be configured in - linuxbridge_conf.ini to specify the names of the physical networks - managed by the linuxbridge plugin, along with the ranges of VLAN IDs - available on each physical network for allocation to virtual - networks. An entry of the form - "::" specifies a VLAN range on - the named physical network. An entry of the form - "" specifies a named network without making a - range of VLANs available for allocation. Networks specified using - either form are available for adminstrators to create provider flat - networks and provider VLANs. Multiple VLAN ranges can be specified - for the same physical network. - - The following example linuxbridge_conf.ini entry shows three - physical networks that can be used to create provider networks, with - ranges of VLANs available for allocation on two of them: - - [VLANS] - network_vlan_ranges = physnet1:1000:2999,physnet1:3000:3999,physnet2,physnet3:1:4094 - - -# -- Agent configuration - -- Edit the configuration file: - etc/neutron/plugins/linuxbridge/linuxbridge_conf.ini - -- Copy neutron/plugins/linuxbridge/agent/linuxbridge_neutron_agent.py - and etc/neutron/plugins/linuxbridge/linuxbridge_conf.ini - to the compute node. - -- Copy the neutron.conf file to the compute node - - Note: debug and logging information should be updated in etc/neutron.conf - -- On each compute node, the network_interface_mappings must be - configured in linuxbridge_conf.ini to map each physical network name - to the physical interface connecting the node to that physical - network. Entries are of the form - ":". For example, one compute - node may use the following physical_inteface_mappings entries: - - [LINUX_BRIDGE] - physical_interface_mappings = physnet1:eth1,physnet2:eth2,physnet3:eth3 - - while another might use: - - [LINUX_BRIDGE] - physical_interface_mappings = physnet1:em3,physnet2:em2,physnet3:em1 - - -$ Run the following: - python linuxbridge_neutron_agent.py --config-file neutron.conf - --config-file linuxbridge_conf.ini - - Note that the the user running the agent must have sudo priviliges - to run various networking commands. Also, the agent can be - configured to use neutron-rootwrap, limiting what commands it can - run via sudo. See http://wiki.openstack.org/Packager/Rootwrap for - details on rootwrap. - - As an alternative to coping the agent python file, if neutron is - installed on the compute node, the agent can be run as - bin/neutron-linuxbridge-agent. diff --git a/neutron/plugins/linuxbridge/__init__.py b/neutron/plugins/linuxbridge/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/neutron/plugins/linuxbridge/agent/__init__.py b/neutron/plugins/linuxbridge/agent/__init__.py deleted file mode 100644 index e69de29bb..000000000 diff --git a/neutron/plugins/linuxbridge/agent/linuxbridge_neutron_agent.py b/neutron/plugins/linuxbridge/agent/linuxbridge_neutron_agent.py deleted file mode 100755 index 5db728655..000000000 --- a/neutron/plugins/linuxbridge/agent/linuxbridge_neutron_agent.py +++ /dev/null @@ -1,1026 +0,0 @@ -#!/usr/bin/env python -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012 Cisco Systems, Inc. -# 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. -# -# -# Performs per host Linux Bridge configuration for Neutron. -# Based on the structure of the OpenVSwitch agent in the -# Neutron OpenVSwitch Plugin. -# @author: Sumit Naiksatam, Cisco Systems, Inc. - -import os -import sys -import time - -import eventlet -eventlet.monkey_patch() - -from oslo.config import cfg - -from neutron.agent import l2population_rpc as l2pop_rpc -from neutron.agent.linux import ip_lib -from neutron.agent.linux import utils -from neutron.agent import rpc as agent_rpc -from neutron.agent import securitygroups_rpc as sg_rpc -from neutron.common import config as common_config -from neutron.common import constants -from neutron.common import exceptions -from neutron.common import rpc_compat -from neutron.common import topics -from neutron.common import utils as q_utils -from neutron import context -from neutron.openstack.common import log as logging -from neutron.openstack.common import loopingcall -from neutron.plugins.common import constants as p_const -from neutron.plugins.linuxbridge.common import config # noqa -from neutron.plugins.linuxbridge.common import constants as lconst - - -LOG = logging.getLogger(__name__) - -BRIDGE_NAME_PREFIX = "brq" -TAP_INTERFACE_PREFIX = "tap" -BRIDGE_FS = "/sys/devices/virtual/net/" -BRIDGE_NAME_PLACEHOLDER = "bridge_name" -BRIDGE_INTERFACES_FS = BRIDGE_FS + BRIDGE_NAME_PLACEHOLDER + "/brif/" -DEVICE_NAME_PLACEHOLDER = "device_name" -BRIDGE_PORT_FS_FOR_DEVICE = BRIDGE_FS + DEVICE_NAME_PLACEHOLDER + "/brport" -VXLAN_INTERFACE_PREFIX = "vxlan-" - - -class NetworkSegment: - def __init__(self, network_type, physical_network, segmentation_id): - self.network_type = network_type - self.physical_network = physical_network - self.segmentation_id = segmentation_id - - -class LinuxBridgeManager: - def __init__(self, interface_mappings, root_helper): - self.interface_mappings = interface_mappings - self.root_helper = root_helper - self.ip = ip_lib.IPWrapper(self.root_helper) - # VXLAN related parameters: - self.local_ip = cfg.CONF.VXLAN.local_ip - self.vxlan_mode = lconst.VXLAN_NONE - if cfg.CONF.VXLAN.enable_vxlan: - self.local_int = self.get_interface_by_ip(self.local_ip) - if self.local_int: - self.check_vxlan_support() - else: - LOG.warning(_('VXLAN is enabled, a valid local_ip ' - 'must be provided')) - # Store network mapping to segments - self.network_map = {} - - def interface_exists_on_bridge(self, bridge, interface): - directory = '/sys/class/net/%s/brif' % bridge - for filename in os.listdir(directory): - if filename == interface: - return True - return False - - def get_bridge_name(self, network_id): - if not network_id: - LOG.warning(_("Invalid Network ID, will lead to incorrect bridge" - "name")) - bridge_name = BRIDGE_NAME_PREFIX + network_id[0:11] - return bridge_name - - def get_subinterface_name(self, physical_interface, vlan_id): - if not vlan_id: - LOG.warning(_("Invalid VLAN ID, will lead to incorrect " - "subinterface name")) - subinterface_name = '%s.%s' % (physical_interface, vlan_id) - return subinterface_name - - def get_tap_device_name(self, interface_id): - if not interface_id: - LOG.warning(_("Invalid Interface ID, will lead to incorrect " - "tap device name")) - tap_device_name = TAP_INTERFACE_PREFIX + interface_id[0:11] - return tap_device_name - - def get_vxlan_device_name(self, segmentation_id): - if 0 <= int(segmentation_id) <= constants.MAX_VXLAN_VNI: - return VXLAN_INTERFACE_PREFIX + str(segmentation_id) - else: - LOG.warning(_("Invalid Segmentation ID: %s, will lead to " - "incorrect vxlan device name"), segmentation_id) - - def get_all_neutron_bridges(self): - neutron_bridge_list = [] - bridge_list = os.listdir(BRIDGE_FS) - for bridge in bridge_list: - if bridge.startswith(BRIDGE_NAME_PREFIX): - neutron_bridge_list.append(bridge) - return neutron_bridge_list - - def get_interfaces_on_bridge(self, bridge_name): - if ip_lib.device_exists(bridge_name, root_helper=self.root_helper): - bridge_interface_path = BRIDGE_INTERFACES_FS.replace( - BRIDGE_NAME_PLACEHOLDER, bridge_name) - return os.listdir(bridge_interface_path) - else: - return [] - - def get_tap_devices_count(self, bridge_name): - bridge_interface_path = BRIDGE_INTERFACES_FS.replace( - BRIDGE_NAME_PLACEHOLDER, bridge_name) - try: - if_list = os.listdir(bridge_interface_path) - return len([interface for interface in if_list if - interface.startswith(TAP_INTERFACE_PREFIX)]) - except OSError: - return 0 - - def get_interface_by_ip(self, ip): - for device in self.ip.get_devices(): - if device.addr.list(to=ip): - return device.name - - def get_bridge_for_tap_device(self, tap_device_name): - bridges = self.get_all_neutron_bridges() - for bridge in bridges: - interfaces = self.get_interfaces_on_bridge(bridge) - if tap_device_name in interfaces: - return bridge - - return None - - def is_device_on_bridge(self, device_name): - if not device_name: - return False - else: - bridge_port_path = BRIDGE_PORT_FS_FOR_DEVICE.replace( - DEVICE_NAME_PLACEHOLDER, device_name) - return os.path.exists(bridge_port_path) - - def ensure_vlan_bridge(self, network_id, physical_interface, vlan_id): - """Create a vlan and bridge unless they already exist.""" - interface = self.ensure_vlan(physical_interface, vlan_id) - bridge_name = self.get_bridge_name(network_id) - ips, gateway = self.get_interface_details(interface) - if self.ensure_bridge(bridge_name, interface, ips, gateway): - return interface - - def ensure_vxlan_bridge(self, network_id, segmentation_id): - """Create a vxlan and bridge unless they already exist.""" - interface = self.ensure_vxlan(segmentation_id) - if not interface: - LOG.error(_("Failed creating vxlan interface for " - "%(segmentation_id)s"), - {segmentation_id: segmentation_id}) - return - bridge_name = self.get_bridge_name(network_id) - self.ensure_bridge(bridge_name, interface) - return interface - - def get_interface_details(self, interface): - device = self.ip.device(interface) - ips = device.addr.list(scope='global') - - # Update default gateway if necessary - gateway = device.route.get_gateway(scope='global') - return ips, gateway - - def ensure_flat_bridge(self, network_id, physical_interface): - """Create a non-vlan bridge unless it already exists.""" - bridge_name = self.get_bridge_name(network_id) - ips, gateway = self.get_interface_details(physical_interface) - if self.ensure_bridge(bridge_name, physical_interface, ips, gateway): - return physical_interface - - def ensure_local_bridge(self, network_id): - """Create a local bridge unless it already exists.""" - bridge_name = self.get_bridge_name(network_id) - return self.ensure_bridge(bridge_name) - - def ensure_vlan(self, physical_interface, vlan_id): - """Create a vlan unless it already exists.""" - interface = self.get_subinterface_name(physical_interface, vlan_id) - if not ip_lib.device_exists(interface, root_helper=self.root_helper): - LOG.debug(_("Creating subinterface %(interface)s for " - "VLAN %(vlan_id)s on interface " - "%(physical_interface)s"), - {'interface': interface, 'vlan_id': vlan_id, - 'physical_interface': physical_interface}) - if utils.execute(['ip', 'link', 'add', 'link', - physical_interface, - 'name', interface, 'type', 'vlan', 'id', - vlan_id], root_helper=self.root_helper): - return - if utils.execute(['ip', 'link', 'set', - interface, 'up'], root_helper=self.root_helper): - return - LOG.debug(_("Done creating subinterface %s"), interface) - return interface - - def ensure_vxlan(self, segmentation_id): - """Create a vxlan unless it already exists.""" - interface = self.get_vxlan_device_name(segmentation_id) - if not ip_lib.device_exists(interface, root_helper=self.root_helper): - LOG.debug(_("Creating vxlan interface %(interface)s for " - "VNI %(segmentation_id)s"), - {'interface': interface, - 'segmentation_id': segmentation_id}) - args = {'dev': self.local_int} - if self.vxlan_mode == lconst.VXLAN_MCAST: - args['group'] = cfg.CONF.VXLAN.vxlan_group - if cfg.CONF.VXLAN.ttl: - args['ttl'] = cfg.CONF.VXLAN.ttl - if cfg.CONF.VXLAN.tos: - args['tos'] = cfg.CONF.VXLAN.tos - if cfg.CONF.VXLAN.l2_population: - args['proxy'] = True - int_vxlan = self.ip.add_vxlan(interface, segmentation_id, **args) - int_vxlan.link.set_up() - LOG.debug(_("Done creating vxlan interface %s"), interface) - return interface - - def update_interface_ip_details(self, destination, source, ips, - gateway): - if ips or gateway: - dst_device = self.ip.device(destination) - src_device = self.ip.device(source) - - # Append IP's to bridge if necessary - if ips: - for ip in ips: - dst_device.addr.add(ip_version=ip['ip_version'], - cidr=ip['cidr'], - broadcast=ip['broadcast']) - - if gateway: - # Ensure that the gateway can be updated by changing the metric - metric = 100 - if 'metric' in gateway: - metric = gateway['metric'] - 1 - dst_device.route.add_gateway(gateway=gateway['gateway'], - metric=metric) - src_device.route.delete_gateway(gateway=gateway['gateway']) - - # Remove IP's from interface - if ips: - for ip in ips: - src_device.addr.delete(ip_version=ip['ip_version'], - cidr=ip['cidr']) - - def _bridge_exists_and_ensure_up(self, bridge_name): - """Check if the bridge exists and make sure it is up.""" - br = ip_lib.IPDevice(bridge_name, self.root_helper) - try: - # If the device doesn't exist this will throw a RuntimeError - br.link.set_up() - except RuntimeError: - return False - return True - - def ensure_bridge(self, bridge_name, interface=None, ips=None, - gateway=None): - """Create a bridge unless it already exists.""" - # _bridge_exists_and_ensure_up instead of device_exists is used here - # because there are cases where the bridge exists but it's not UP, - # for example: - # 1) A greenthread was executing this function and had not yet executed - # "ip link set bridge_name up" before eventlet switched to this - # thread running the same function - # 2) The Nova VIF driver was running concurrently and had just created - # the bridge, but had not yet put it UP - if not self._bridge_exists_and_ensure_up(bridge_name): - LOG.debug(_("Starting bridge %(bridge_name)s for subinterface " - "%(interface)s"), - {'bridge_name': bridge_name, 'interface': interface}) - if utils.execute(['brctl', 'addbr', bridge_name], - root_helper=self.root_helper): - return - if utils.execute(['brctl', 'setfd', bridge_name, - str(0)], root_helper=self.root_helper): - return - if utils.execute(['brctl', 'stp', bridge_name, - 'off'], root_helper=self.root_helper): - return - if utils.execute(['ip', 'link', 'set', bridge_name, - 'up'], root_helper=self.root_helper): - return - LOG.debug(_("Done starting bridge %(bridge_name)s for " - "subinterface %(interface)s"), - {'bridge_name': bridge_name, 'interface': interface}) - - if not interface: - return bridge_name - - # Update IP info if necessary - self.update_interface_ip_details(bridge_name, interface, ips, gateway) - - # Check if the interface is part of the bridge - if not self.interface_exists_on_bridge(bridge_name, interface): - try: - # Check if the interface is not enslaved in another bridge - if self.is_device_on_bridge(interface): - bridge = self.get_bridge_for_tap_device(interface) - utils.execute(['brctl', 'delif', bridge, interface], - root_helper=self.root_helper) - - utils.execute(['brctl', 'addif', bridge_name, interface], - root_helper=self.root_helper) - except Exception as e: - LOG.error(_("Unable to add %(interface)s to %(bridge_name)s! " - "Exception: %(e)s"), - {'interface': interface, 'bridge_name': bridge_name, - 'e': e}) - return - return bridge_name - - def ensure_physical_in_bridge(self, network_id, - network_type, - physical_network, - segmentation_id): - if network_type == p_const.TYPE_VXLAN: - if self.vxlan_mode == lconst.VXLAN_NONE: - LOG.error(_("Unable to add vxlan interface for network %s"), - network_id) - return - return self.ensure_vxlan_bridge(network_id, segmentation_id) - - physical_interface = self.interface_mappings.get(physical_network) - if not physical_interface: - LOG.error(_("No mapping for physical network %s"), - physical_network) - return - if network_type == p_const.TYPE_FLAT: - return self.ensure_flat_bridge(network_id, physical_interface) - elif network_type == p_const.TYPE_VLAN: - return self.ensure_vlan_bridge(network_id, physical_interface, - segmentation_id) - else: - LOG.error(_("Unknown network_type %(network_type)s for network " - "%(network_id)s."), {network_type: network_type, - network_id: network_id}) - - def add_tap_interface(self, network_id, network_type, physical_network, - segmentation_id, tap_device_name): - """Add tap interface. - - If a VIF has been plugged into a network, this function will - add the corresponding tap device to the relevant bridge. - """ - if not ip_lib.device_exists(tap_device_name, - root_helper=self.root_helper): - LOG.debug(_("Tap device: %s does not exist on " - "this host, skipped"), tap_device_name) - return False - - bridge_name = self.get_bridge_name(network_id) - if network_type == p_const.TYPE_LOCAL: - self.ensure_local_bridge(network_id) - elif not self.ensure_physical_in_bridge(network_id, - network_type, - physical_network, - segmentation_id): - return False - - # Check if device needs to be added to bridge - tap_device_in_bridge = self.get_bridge_for_tap_device(tap_device_name) - if not tap_device_in_bridge: - data = {'tap_device_name': tap_device_name, - 'bridge_name': bridge_name} - msg = _("Adding device %(tap_device_name)s to bridge " - "%(bridge_name)s") % data - LOG.debug(msg) - if utils.execute(['brctl', 'addif', bridge_name, tap_device_name], - root_helper=self.root_helper): - return False - else: - data = {'tap_device_name': tap_device_name, - 'bridge_name': bridge_name} - msg = _("%(tap_device_name)s already exists on bridge " - "%(bridge_name)s") % data - LOG.debug(msg) - return True - - def add_interface(self, network_id, network_type, physical_network, - segmentation_id, port_id): - self.network_map[network_id] = NetworkSegment(network_type, - physical_network, - segmentation_id) - tap_device_name = self.get_tap_device_name(port_id) - return self.add_tap_interface(network_id, network_type, - physical_network, segmentation_id, - tap_device_name) - - def delete_vlan_bridge(self, bridge_name): - if ip_lib.device_exists(bridge_name, root_helper=self.root_helper): - interfaces_on_bridge = self.get_interfaces_on_bridge(bridge_name) - for interface in interfaces_on_bridge: - self.remove_interface(bridge_name, interface) - - if interface.startswith(VXLAN_INTERFACE_PREFIX): - self.delete_vxlan(interface) - continue - - for physical_interface in self.interface_mappings.itervalues(): - if (interface.startswith(physical_interface)): - ips, gateway = self.get_interface_details(bridge_name) - if ips: - # This is a flat network or a VLAN interface that - # was setup outside of neutron => return IP's from - # bridge to interface - self.update_interface_ip_details(interface, - bridge_name, - ips, gateway) - elif physical_interface != interface: - self.delete_vlan(interface) - - LOG.debug(_("Deleting bridge %s"), bridge_name) - if utils.execute(['ip', 'link', 'set', bridge_name, 'down'], - root_helper=self.root_helper): - return - if utils.execute(['brctl', 'delbr', bridge_name], - root_helper=self.root_helper): - return - LOG.debug(_("Done deleting bridge %s"), bridge_name) - - else: - LOG.error(_("Cannot delete bridge %s, does not exist"), - bridge_name) - - def remove_empty_bridges(self): - for network_id in self.network_map.keys(): - bridge_name = self.get_bridge_name(network_id) - if not self.get_tap_devices_count(bridge_name): - self.delete_vlan_bridge(bridge_name) - del self.network_map[network_id] - - def remove_interface(self, bridge_name, interface_name): - if ip_lib.device_exists(bridge_name, root_helper=self.root_helper): - if not self.is_device_on_bridge(interface_name): - return True - LOG.debug(_("Removing device %(interface_name)s from bridge " - "%(bridge_name)s"), - {'interface_name': interface_name, - 'bridge_name': bridge_name}) - if utils.execute(['brctl', 'delif', bridge_name, interface_name], - root_helper=self.root_helper): - return False - LOG.debug(_("Done removing device %(interface_name)s from bridge " - "%(bridge_name)s"), - {'interface_name': interface_name, - 'bridge_name': bridge_name}) - return True - else: - LOG.debug(_("Cannot remove device %(interface_name)s bridge " - "%(bridge_name)s does not exist"), - {'interface_name': interface_name, - 'bridge_name': bridge_name}) - return False - - def delete_vlan(self, interface): - if ip_lib.device_exists(interface, root_helper=self.root_helper): - LOG.debug(_("Deleting subinterface %s for vlan"), interface) - if utils.execute(['ip', 'link', 'set', interface, 'down'], - root_helper=self.root_helper): - return - if utils.execute(['ip', 'link', 'delete', interface], - root_helper=self.root_helper): - return - LOG.debug(_("Done deleting subinterface %s"), interface) - - def delete_vxlan(self, interface): - if ip_lib.device_exists(interface, root_helper=self.root_helper): - LOG.debug(_("Deleting vxlan interface %s for vlan"), - interface) - int_vxlan = self.ip.device(interface) - int_vxlan.link.set_down() - int_vxlan.link.delete() - LOG.debug(_("Done deleting vxlan interface %s"), interface) - - def get_tap_devices(self): - devices = set() - for device in os.listdir(BRIDGE_FS): - if device.startswith(TAP_INTERFACE_PREFIX): - devices.add(device) - return devices - - def vxlan_ucast_supported(self): - if not cfg.CONF.VXLAN.l2_population: - return False - if not ip_lib.iproute_arg_supported( - ['bridge', 'fdb'], 'append', self.root_helper): - LOG.warning(_('Option "%(option)s" must be supported by command ' - '"%(command)s" to enable %(mode)s mode') % - {'option': 'append', - 'command': 'bridge fdb', - 'mode': 'VXLAN UCAST'}) - return False - for segmentation_id in range(1, constants.MAX_VXLAN_VNI + 1): - if not ip_lib.device_exists( - self.get_vxlan_device_name(segmentation_id), - root_helper=self.root_helper): - break - else: - LOG.error(_('No valid Segmentation ID to perform UCAST test.')) - return False - - test_iface = self.ensure_vxlan(segmentation_id) - try: - utils.execute( - cmd=['bridge', 'fdb', 'append', constants.FLOODING_ENTRY[0], - 'dev', test_iface, 'dst', '1.1.1.1'], - root_helper=self.root_helper) - return True - except RuntimeError: - return False - finally: - self.delete_vxlan(test_iface) - - def vxlan_mcast_supported(self): - if not cfg.CONF.VXLAN.vxlan_group: - LOG.warning(_('VXLAN muticast group must be provided in ' - 'vxlan_group option to enable VXLAN MCAST mode')) - return False - if not ip_lib.iproute_arg_supported( - ['ip', 'link', 'add', 'type', 'vxlan'], - 'proxy', self.root_helper): - LOG.warning(_('Option "%(option)s" must be supported by command ' - '"%(command)s" to enable %(mode)s mode') % - {'option': 'proxy', - 'command': 'ip link add type vxlan', - 'mode': 'VXLAN MCAST'}) - - return False - return True - - def vxlan_module_supported(self): - try: - utils.execute(cmd=['modinfo', 'vxlan']) - return True - except RuntimeError: - return False - - def check_vxlan_support(self): - self.vxlan_mode = lconst.VXLAN_NONE - if not self.vxlan_module_supported(): - LOG.error(_('Linux kernel vxlan module and iproute2 3.8 or above ' - 'are required to enable VXLAN.')) - raise exceptions.VxlanNetworkUnsupported() - - if self.vxlan_ucast_supported(): - self.vxlan_mode = lconst.VXLAN_UCAST - elif self.vxlan_mcast_supported(): - self.vxlan_mode = lconst.VXLAN_MCAST - else: - raise exceptions.VxlanNetworkUnsupported() - LOG.debug(_('Using %s VXLAN mode'), self.vxlan_mode) - - def fdb_ip_entry_exists(self, mac, ip, interface): - entries = utils.execute(['ip', 'neigh', 'show', 'to', ip, - 'dev', interface], - root_helper=self.root_helper) - return mac in entries - - def fdb_bridge_entry_exists(self, mac, interface, agent_ip=None): - entries = utils.execute(['bridge', 'fdb', 'show', 'dev', interface], - root_helper=self.root_helper) - if not agent_ip: - return mac in entries - - return (agent_ip in entries and mac in entries) - - def add_fdb_ip_entry(self, mac, ip, interface): - utils.execute(['ip', 'neigh', 'replace', ip, 'lladdr', mac, - 'dev', interface, 'nud', 'permanent'], - root_helper=self.root_helper, - check_exit_code=False) - - def remove_fdb_ip_entry(self, mac, ip, interface): - utils.execute(['ip', 'neigh', 'del', ip, 'lladdr', mac, - 'dev', interface], - root_helper=self.root_helper, - check_exit_code=False) - - def add_fdb_bridge_entry(self, mac, agent_ip, interface, operation="add"): - utils.execute(['bridge', 'fdb', operation, mac, 'dev', interface, - 'dst', agent_ip], - root_helper=self.root_helper, - check_exit_code=False) - - def remove_fdb_bridge_entry(self, mac, agent_ip, interface): - utils.execute(['bridge', 'fdb', 'del', mac, 'dev', interface, - 'dst', agent_ip], - root_helper=self.root_helper, - check_exit_code=False) - - def add_fdb_entries(self, agent_ip, ports, interface): - for mac, ip in ports: - if mac != constants.FLOODING_ENTRY[0]: - self.add_fdb_ip_entry(mac, ip, interface) - self.add_fdb_bridge_entry(mac, agent_ip, interface) - elif self.vxlan_mode == lconst.VXLAN_UCAST: - if self.fdb_bridge_entry_exists(mac, interface): - self.add_fdb_bridge_entry(mac, agent_ip, interface, - "append") - else: - self.add_fdb_bridge_entry(mac, agent_ip, interface) - - def remove_fdb_entries(self, agent_ip, ports, interface): - for mac, ip in ports: - if mac != constants.FLOODING_ENTRY[0]: - self.remove_fdb_ip_entry(mac, ip, interface) - self.remove_fdb_bridge_entry(mac, agent_ip, interface) - elif self.vxlan_mode == lconst.VXLAN_UCAST: - self.remove_fdb_bridge_entry(mac, agent_ip, interface) - - -class LinuxBridgeRpcCallbacks(rpc_compat.RpcCallback, - sg_rpc.SecurityGroupAgentRpcCallbackMixin, - l2pop_rpc.L2populationRpcCallBackMixin): - - # Set RPC API version to 1.0 by default. - # history - # 1.1 Support Security Group RPC - RPC_API_VERSION = '1.1' - - def __init__(self, context, agent): - super(LinuxBridgeRpcCallbacks, self).__init__() - self.context = context - self.agent = agent - self.sg_agent = agent - - def network_delete(self, context, **kwargs): - LOG.debug(_("network_delete received")) - network_id = kwargs.get('network_id') - bridge_name = self.agent.br_mgr.get_bridge_name(network_id) - LOG.debug(_("Delete %s"), bridge_name) - self.agent.br_mgr.delete_vlan_bridge(bridge_name) - - def port_update(self, context, **kwargs): - port_id = kwargs['port']['id'] - tap_name = self.agent.br_mgr.get_tap_device_name(port_id) - # Put the tap name in the updated_devices set. - # Do not store port details, as if they're used for processing - # notifications there is no guarantee the notifications are - # processed in the same order as the relevant API requests. - self.agent.updated_devices.add(tap_name) - LOG.debug(_("port_update RPC received for port: %s"), port_id) - - def fdb_add(self, context, fdb_entries): - LOG.debug(_("fdb_add received")) - for network_id, values in fdb_entries.items(): - segment = self.agent.br_mgr.network_map.get(network_id) - if not segment: - return - - if segment.network_type != p_const.TYPE_VXLAN: - return - - interface = self.agent.br_mgr.get_vxlan_device_name( - segment.segmentation_id) - - agent_ports = values.get('ports') - for agent_ip, ports in agent_ports.items(): - if agent_ip == self.agent.br_mgr.local_ip: - continue - - self.agent.br_mgr.add_fdb_entries(agent_ip, - ports, - interface) - - def fdb_remove(self, context, fdb_entries): - LOG.debug(_("fdb_remove received")) - for network_id, values in fdb_entries.items(): - segment = self.agent.br_mgr.network_map.get(network_id) - if not segment: - return - - if segment.network_type != p_const.TYPE_VXLAN: - return - - interface = self.agent.br_mgr.get_vxlan_device_name( - segment.segmentation_id) - - agent_ports = values.get('ports') - for agent_ip, ports in agent_ports.items(): - if agent_ip == self.agent.br_mgr.local_ip: - continue - - self.agent.br_mgr.remove_fdb_entries(agent_ip, - ports, - interface) - - def _fdb_chg_ip(self, context, fdb_entries): - LOG.debug(_("update chg_ip received")) - for network_id, agent_ports in fdb_entries.items(): - segment = self.agent.br_mgr.network_map.get(network_id) - if not segment: - return - - if segment.network_type != p_const.TYPE_VXLAN: - return - - interface = self.agent.br_mgr.get_vxlan_device_name( - segment.segmentation_id) - - for agent_ip, state in agent_ports.items(): - if agent_ip == self.agent.br_mgr.local_ip: - continue - - after = state.get('after') - for mac, ip in after: - self.agent.br_mgr.add_fdb_ip_entry(mac, ip, interface) - - before = state.get('before') - for mac, ip in before: - self.agent.br_mgr.remove_fdb_ip_entry(mac, ip, interface) - - def fdb_update(self, context, fdb_entries): - LOG.debug(_("fdb_update received")) - for action, values in fdb_entries.items(): - method = '_fdb_' + action - if not hasattr(self, method): - raise NotImplementedError() - - getattr(self, method)(context, values) - - -class LinuxBridgePluginApi(agent_rpc.PluginApi, - sg_rpc.SecurityGroupServerRpcApiMixin): - pass - - -class LinuxBridgeNeutronAgentRPC(sg_rpc.SecurityGroupAgentRpcMixin): - - def __init__(self, interface_mappings, polling_interval, - root_helper): - self.polling_interval = polling_interval - self.root_helper = root_helper - self.setup_linux_bridge(interface_mappings) - configurations = {'interface_mappings': interface_mappings} - if self.br_mgr.vxlan_mode != lconst.VXLAN_NONE: - configurations['tunneling_ip'] = self.br_mgr.local_ip - configurations['tunnel_types'] = [p_const.TYPE_VXLAN] - configurations['l2_population'] = cfg.CONF.VXLAN.l2_population - self.agent_state = { - 'binary': 'neutron-linuxbridge-agent', - 'host': cfg.CONF.host, - 'topic': constants.L2_AGENT_TOPIC, - 'configurations': configurations, - 'agent_type': constants.AGENT_TYPE_LINUXBRIDGE, - 'start_flag': True} - - # stores received port_updates for processing by the main loop - self.updated_devices = set() - self.setup_rpc(interface_mappings.values()) - self.init_firewall() - - def _report_state(self): - try: - devices = len(self.br_mgr.get_tap_devices()) - self.agent_state.get('configurations')['devices'] = devices - self.state_rpc.report_state(self.context, - self.agent_state) - self.agent_state.pop('start_flag', None) - except Exception: - LOG.exception(_("Failed reporting state!")) - - def setup_rpc(self, physical_interfaces): - if physical_interfaces: - mac = utils.get_interface_mac(physical_interfaces[0]) - else: - devices = ip_lib.IPWrapper(self.root_helper).get_devices(True) - if devices: - mac = utils.get_interface_mac(devices[0].name) - else: - LOG.error(_("Unable to obtain MAC address for unique ID. " - "Agent terminated!")) - exit(1) - self.agent_id = '%s%s' % ('lb', (mac.replace(":", ""))) - LOG.info(_("RPC agent_id: %s"), self.agent_id) - - self.topic = topics.AGENT - self.plugin_rpc = LinuxBridgePluginApi(topics.PLUGIN) - self.state_rpc = agent_rpc.PluginReportStateAPI(topics.PLUGIN) - # RPC network init - self.context = context.get_admin_context_without_session() - # Handle updates from service - self.endpoints = [LinuxBridgeRpcCallbacks(self.context, self)] - # Define the listening consumers for the agent - consumers = [[topics.PORT, topics.UPDATE], - [topics.NETWORK, topics.DELETE], - [topics.SECURITY_GROUP, topics.UPDATE]] - if cfg.CONF.VXLAN.l2_population: - consumers.append([topics.L2POPULATION, - topics.UPDATE, cfg.CONF.host]) - self.connection = agent_rpc.create_consumers(self.endpoints, - self.topic, - consumers) - report_interval = cfg.CONF.AGENT.report_interval - if report_interval: - heartbeat = loopingcall.FixedIntervalLoopingCall( - self._report_state) - heartbeat.start(interval=report_interval) - - def setup_linux_bridge(self, interface_mappings): - self.br_mgr = LinuxBridgeManager(interface_mappings, self.root_helper) - - def remove_port_binding(self, network_id, interface_id): - bridge_name = self.br_mgr.get_bridge_name(network_id) - tap_device_name = self.br_mgr.get_tap_device_name(interface_id) - return self.br_mgr.remove_interface(bridge_name, tap_device_name) - - def process_network_devices(self, device_info): - resync_a = False - resync_b = False - - self.prepare_devices_filter(device_info.get('added')) - - if device_info.get('updated'): - self.refresh_firewall() - - # Updated devices are processed the same as new ones, as their - # admin_state_up may have changed. The set union prevents duplicating - # work when a device is new and updated in the same polling iteration. - devices_added_updated = (set(device_info.get('added')) - | set(device_info.get('updated'))) - if devices_added_updated: - resync_a = self.treat_devices_added_updated(devices_added_updated) - - if device_info.get('removed'): - resync_b = self.treat_devices_removed(device_info['removed']) - # If one of the above operations fails => resync with plugin - return (resync_a | resync_b) - - def treat_devices_added_updated(self, devices): - resync = False - - for device in devices: - LOG.debug(_("Treating added or updated device: %s"), device) - try: - details = self.plugin_rpc.get_device_details(self.context, - device, - self.agent_id) - except Exception as e: - LOG.debug(_("Unable to get port details for " - "%(device)s: %(e)s"), - {'device': device, 'e': e}) - resync = True - continue - if 'port_id' in details: - LOG.info(_("Port %(device)s updated. Details: %(details)s"), - {'device': device, 'details': details}) - if details['admin_state_up']: - # create the networking for the port - network_type = details.get('network_type') - if network_type: - segmentation_id = details.get('segmentation_id') - else: - # compatibility with pre-Havana RPC vlan_id encoding - vlan_id = details.get('vlan_id') - (network_type, - segmentation_id) = lconst.interpret_vlan_id(vlan_id) - if self.br_mgr.add_interface(details['network_id'], - network_type, - details['physical_network'], - segmentation_id, - details['port_id']): - - # update plugin about port status - self.plugin_rpc.update_device_up(self.context, - device, - self.agent_id, - cfg.CONF.host) - else: - self.plugin_rpc.update_device_down(self.context, - device, - self.agent_id, - cfg.CONF.host) - else: - self.remove_port_binding(details['network_id'], - details['port_id']) - else: - LOG.info(_("Device %s not defined on plugin"), device) - return resync - - def treat_devices_removed(self, devices): - resync = False - self.remove_devices_filter(devices) - for device in devices: - LOG.info(_("Attachment %s removed"), device) - details = None - try: - details = self.plugin_rpc.update_device_down(self.context, - device, - self.agent_id, - cfg.CONF.host) - except Exception as e: - LOG.debug(_("port_removed failed for %(device)s: %(e)s"), - {'device': device, 'e': e}) - resync = True - if details and details['exists']: - LOG.info(_("Port %s updated."), device) - else: - LOG.debug(_("Device %s not defined on plugin"), device) - self.br_mgr.remove_empty_bridges() - return resync - - def scan_devices(self, registered_devices, updated_devices): - curr_devices = self.br_mgr.get_tap_devices() - device_info = {} - device_info['current'] = curr_devices - device_info['added'] = curr_devices - registered_devices - # we don't want to process updates for devices that don't exist - device_info['updated'] = updated_devices & curr_devices - # we need to clean up after devices are removed - device_info['removed'] = registered_devices - curr_devices - return device_info - - def _device_info_has_changes(self, device_info): - return (device_info.get('added') - or device_info.get('updated') - or device_info.get('removed')) - - def daemon_loop(self): - sync = True - devices = set() - - LOG.info(_("LinuxBridge Agent RPC Daemon Started!")) - - while True: - start = time.time() - if sync: - LOG.info(_("Agent out of sync with plugin!")) - devices.clear() - sync = False - device_info = {} - # Save updated devices dict to perform rollback in case - # resync would be needed, and then clear self.updated_devices. - # As the greenthread should not yield between these - # two statements, this will should be thread-safe. - updated_devices_copy = self.updated_devices - self.updated_devices = set() - try: - device_info = self.scan_devices(devices, updated_devices_copy) - if self._device_info_has_changes(device_info): - LOG.debug(_("Agent loop found changes! %s"), device_info) - # If treat devices fails - indicates must resync with - # plugin - sync = self.process_network_devices(device_info) - devices = device_info['current'] - except Exception: - LOG.exception(_("Error in agent loop. Devices info: %s"), - device_info) - sync = True - # Restore devices that were removed from this set earlier - # without overwriting ones that may have arrived since. - self.updated_devices |= updated_devices_copy - - # sleep till end of polling interval - elapsed = (time.time() - start) - if (elapsed < self.polling_interval): - time.sleep(self.polling_interval - elapsed) - else: - LOG.debug(_("Loop iteration exceeded interval " - "(%(polling_interval)s vs. %(elapsed)s)!"), - {'polling_interval': self.polling_interval, - 'elapsed': elapsed}) - - -def main(): - common_config.init(sys.argv[1:]) - - common_config.setup_logging(cfg.CONF) - try: - interface_mappings = q_utils.parse_mappings( - cfg.CONF.LINUX_BRIDGE.physical_interface_mappings) - except ValueError as e: - LOG.error(_("Parsing physical_interface_mappings failed: %s." - " Agent terminated!"), e) - sys.exit(1) - LOG.info(_("Interface mappings: %s"), interface_mappings) - - polling_interval = cfg.CONF.AGENT.polling_interval - root_helper = cfg.CONF.AGENT.root_helper - agent = LinuxBridgeNeutronAgentRPC(interface_mappings, - polling_interval, - root_helper) - LOG.info(_("Agent initialized successfully, now running... ")) - agent.daemon_loop() - sys.exit(0) - - -if __name__ == "__main__": - main() diff --git a/neutron/plugins/linuxbridge/common/__init__.py b/neutron/plugins/linuxbridge/common/__init__.py deleted file mode 100644 index 5bb15232d..000000000 --- a/neutron/plugins/linuxbridge/common/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012 Cisco Systems, Inc. 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: Sumit Naiksatam, Cisco Systems, Inc. diff --git a/neutron/plugins/linuxbridge/common/config.py b/neutron/plugins/linuxbridge/common/config.py deleted file mode 100644 index 8736d63a6..000000000 --- a/neutron/plugins/linuxbridge/common/config.py +++ /dev/null @@ -1,78 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012 Cisco Systems, Inc. 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: Sumit Naiksatam, Cisco Systems, Inc. -# @author: Rohit Agarwalla, Cisco Systems, Inc. - -from oslo.config import cfg - -from neutron.agent.common import config - -DEFAULT_VLAN_RANGES = [] -DEFAULT_INTERFACE_MAPPINGS = [] -DEFAULT_VXLAN_GROUP = '224.0.0.1' - - -vlan_opts = [ - cfg.StrOpt('tenant_network_type', default='local', - help=_("Network type for tenant networks " - "(local, vlan, or none)")), - cfg.ListOpt('network_vlan_ranges', - default=DEFAULT_VLAN_RANGES, - help=_("List of :: " - "or ")), -] - -vxlan_opts = [ - cfg.BoolOpt('enable_vxlan', default=False, - help=_("Enable VXLAN on the agent. Can be enabled when " - "agent is managed by ml2 plugin using linuxbridge " - "mechanism driver")), - cfg.IntOpt('ttl', - help=_("TTL for vxlan interface protocol packets.")), - cfg.IntOpt('tos', - help=_("TOS for vxlan interface protocol packets.")), - cfg.StrOpt('vxlan_group', default=DEFAULT_VXLAN_GROUP, - help=_("Multicast group for vxlan interface.")), - cfg.StrOpt('local_ip', default='', - help=_("Local IP address of the VXLAN endpoints.")), - cfg.BoolOpt('l2_population', default=False, - help=_("Extension to use alongside ml2 plugin's l2population " - "mechanism driver. It enables the plugin to populate " - "VXLAN forwarding table.")), -] - -bridge_opts = [ - cfg.ListOpt('physical_interface_mappings', - default=DEFAULT_INTERFACE_MAPPINGS, - help=_("List of :")), -] - -agent_opts = [ - cfg.IntOpt('polling_interval', default=2, - help=_("The number of seconds the agent will wait between " - "polling for local device changes.")), - cfg.BoolOpt('rpc_support_old_agents', default=False, - help=_("Enable server RPC compatibility with old agents")), -] - - -cfg.CONF.register_opts(vlan_opts, "VLANS") -cfg.CONF.register_opts(vxlan_opts, "VXLAN") -cfg.CONF.register_opts(bridge_opts, "LINUX_BRIDGE") -cfg.CONF.register_opts(agent_opts, "AGENT") -config.register_agent_state_opts_helper(cfg.CONF) -config.register_root_helper(cfg.CONF) diff --git a/neutron/plugins/linuxbridge/common/constants.py b/neutron/plugins/linuxbridge/common/constants.py deleted file mode 100644 index 6dee88f40..000000000 --- a/neutron/plugins/linuxbridge/common/constants.py +++ /dev/null @@ -1,42 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012 Cisco Systems, Inc. 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: Sumit Naiksatam, Cisco Systems, Inc. - - -from neutron.plugins.common import constants as p_const - - -FLAT_VLAN_ID = -1 -LOCAL_VLAN_ID = -2 - -# Supported VXLAN features -VXLAN_NONE = 'not_supported' -VXLAN_MCAST = 'multicast_flooding' -VXLAN_UCAST = 'unicast_flooding' - - -# TODO(rkukura): Eventually remove this function, which provides -# temporary backward compatibility with pre-Havana RPC and DB vlan_id -# encoding. -def interpret_vlan_id(vlan_id): - """Return (network_type, segmentation_id) tuple for encoded vlan_id.""" - if vlan_id == LOCAL_VLAN_ID: - return (p_const.TYPE_LOCAL, None) - elif vlan_id == FLAT_VLAN_ID: - return (p_const.TYPE_FLAT, None) - else: - return (p_const.TYPE_VLAN, vlan_id) diff --git a/neutron/plugins/linuxbridge/db/__init__.py b/neutron/plugins/linuxbridge/db/__init__.py deleted file mode 100644 index 33daf1f33..000000000 --- a/neutron/plugins/linuxbridge/db/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012 Cisco Systems, Inc. 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: Sumit Naiksatam, Cisco Systems, Inc. -# diff --git a/neutron/plugins/linuxbridge/db/l2network_db_v2.py b/neutron/plugins/linuxbridge/db/l2network_db_v2.py deleted file mode 100644 index 416bd2f59..000000000 --- a/neutron/plugins/linuxbridge/db/l2network_db_v2.py +++ /dev/null @@ -1,238 +0,0 @@ -# Copyright (c) 2012 OpenStack Foundation. -# -# 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 six import moves -from sqlalchemy.orm import exc - -from neutron.common import exceptions as n_exc -import neutron.db.api as db -from neutron.db import models_v2 -from neutron.db import securitygroups_db as sg_db -from neutron import manager -from neutron.openstack.common import log as logging -from neutron.plugins.linuxbridge.common import config # noqa -from neutron.plugins.linuxbridge.common import constants -from neutron.plugins.linuxbridge.db import l2network_models_v2 - -LOG = logging.getLogger(__name__) - - -def sync_network_states(network_vlan_ranges): - """Synchronize network_states table with current configured VLAN ranges.""" - - session = db.get_session() - with session.begin(): - # get existing allocations for all physical networks - allocations = dict() - states = (session.query(l2network_models_v2.NetworkState). - all()) - for state in states: - if state.physical_network not in allocations: - allocations[state.physical_network] = set() - allocations[state.physical_network].add(state) - - # process vlan ranges for each configured physical network - for physical_network, vlan_ranges in network_vlan_ranges.iteritems(): - # determine current configured allocatable vlans for this - # physical network - vlan_ids = set() - for vlan_range in vlan_ranges: - vlan_ids |= set(moves.xrange(vlan_range[0], vlan_range[1] + 1)) - - # remove from table unallocated vlans not currently allocatable - if physical_network in allocations: - for state in allocations[physical_network]: - try: - # see if vlan is allocatable - vlan_ids.remove(state.vlan_id) - except KeyError: - # it's not allocatable, so check if its allocated - if not state.allocated: - # it's not, so remove it from table - LOG.debug(_("Removing vlan %(vlan_id)s on " - "physical network %(physical_network)s" - " from pool"), - {'vlan_id': state.vlan_id, - 'physical_network': physical_network}) - session.delete(state) - del allocations[physical_network] - - # add missing allocatable vlans to table - for vlan_id in sorted(vlan_ids): - state = l2network_models_v2.NetworkState(physical_network, - vlan_id) - session.add(state) - - # remove from table unallocated vlans for any unconfigured physical - # networks - for states in allocations.itervalues(): - for state in states: - if not state.allocated: - LOG.debug(_("Removing vlan %(vlan_id)s on physical " - "network %(physical_network)s" - " from pool"), - {'vlan_id': state.vlan_id, - 'physical_network': state.physical_network}) - session.delete(state) - - -def get_network_state(physical_network, vlan_id): - """Get state of specified network.""" - - session = db.get_session() - try: - state = (session.query(l2network_models_v2.NetworkState). - filter_by(physical_network=physical_network, - vlan_id=vlan_id). - one()) - return state - except exc.NoResultFound: - return None - - -def reserve_network(session): - with session.begin(subtransactions=True): - state = (session.query(l2network_models_v2.NetworkState). - filter_by(allocated=False). - with_lockmode('update'). - first()) - if not state: - raise n_exc.NoNetworkAvailable() - LOG.debug(_("Reserving vlan %(vlan_id)s on physical network " - "%(physical_network)s from pool"), - {'vlan_id': state.vlan_id, - 'physical_network': state.physical_network}) - state.allocated = True - return (state.physical_network, state.vlan_id) - - -def reserve_specific_network(session, physical_network, vlan_id): - with session.begin(subtransactions=True): - try: - state = (session.query(l2network_models_v2.NetworkState). - filter_by(physical_network=physical_network, - vlan_id=vlan_id). - with_lockmode('update'). - one()) - if state.allocated: - if vlan_id == constants.FLAT_VLAN_ID: - raise n_exc.FlatNetworkInUse( - physical_network=physical_network) - else: - raise n_exc.VlanIdInUse(vlan_id=vlan_id, - physical_network=physical_network) - LOG.debug(_("Reserving specific vlan %(vlan_id)s on physical " - "network %(physical_network)s from pool"), - {'vlan_id': vlan_id, - 'physical_network': physical_network}) - state.allocated = True - except exc.NoResultFound: - LOG.debug(_("Reserving specific vlan %(vlan_id)s on physical " - "network %(physical_network)s outside pool"), - {'vlan_id': vlan_id, - 'physical_network': physical_network}) - state = l2network_models_v2.NetworkState(physical_network, vlan_id) - state.allocated = True - session.add(state) - - -def release_network(session, physical_network, vlan_id, network_vlan_ranges): - with session.begin(subtransactions=True): - try: - state = (session.query(l2network_models_v2.NetworkState). - filter_by(physical_network=physical_network, - vlan_id=vlan_id). - with_lockmode('update'). - one()) - state.allocated = False - inside = False - for vlan_range in network_vlan_ranges.get(physical_network, []): - if vlan_id >= vlan_range[0] and vlan_id <= vlan_range[1]: - inside = True - break - if inside: - LOG.debug(_("Releasing vlan %(vlan_id)s on physical network " - "%(physical_network)s to pool"), - {'vlan_id': vlan_id, - 'physical_network': physical_network}) - else: - LOG.debug(_("Releasing vlan %(vlan_id)s on physical network " - "%(physical_network)s outside pool"), - {'vlan_id': vlan_id, - 'physical_network': physical_network}) - session.delete(state) - except exc.NoResultFound: - LOG.warning(_("vlan_id %(vlan_id)s on physical network " - "%(physical_network)s not found"), - {'vlan_id': vlan_id, - 'physical_network': physical_network}) - - -def add_network_binding(session, network_id, physical_network, vlan_id): - with session.begin(subtransactions=True): - binding = l2network_models_v2.NetworkBinding(network_id, - physical_network, vlan_id) - session.add(binding) - - -def get_network_binding(session, network_id): - try: - binding = (session.query(l2network_models_v2.NetworkBinding). - filter_by(network_id=network_id). - one()) - return binding - except exc.NoResultFound: - return - - -def get_port_from_device(device): - """Get port from database.""" - LOG.debug(_("get_port_from_device() called")) - session = db.get_session() - sg_binding_port = sg_db.SecurityGroupPortBinding.port_id - - query = session.query(models_v2.Port, - sg_db.SecurityGroupPortBinding.security_group_id) - query = query.outerjoin(sg_db.SecurityGroupPortBinding, - models_v2.Port.id == sg_binding_port) - query = query.filter(models_v2.Port.id.startswith(device)) - port_and_sgs = query.all() - if not port_and_sgs: - return - port = port_and_sgs[0][0] - plugin = manager.NeutronManager.get_plugin() - port_dict = plugin._make_port_dict(port) - port_dict['security_groups'] = [] - for port_in_db, sg_id in port_and_sgs: - if sg_id: - port_dict['security_groups'].append(sg_id) - port_dict['security_group_rules'] = [] - port_dict['security_group_source_groups'] = [] - port_dict['fixed_ips'] = [ip['ip_address'] - for ip in port['fixed_ips']] - return port_dict - - -def set_port_status(port_id, status): - """Set the port status.""" - LOG.debug(_("set_port_status as %s called"), status) - session = db.get_session() - try: - port = session.query(models_v2.Port).filter_by(id=port_id).one() - port['status'] = status - session.merge(port) - session.flush() - except exc.NoResultFound: - raise n_exc.PortNotFound(port_id=port_id) diff --git a/neutron/plugins/linuxbridge/db/l2network_models_v2.py b/neutron/plugins/linuxbridge/db/l2network_models_v2.py deleted file mode 100644 index 0c08e29c5..000000000 --- a/neutron/plugins/linuxbridge/db/l2network_models_v2.py +++ /dev/null @@ -1,59 +0,0 @@ -# Copyright (c) 2012 OpenStack Foundation. -# -# 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. - -import sqlalchemy as sa - -from neutron.db import model_base - - -class NetworkState(model_base.BASEV2): - """Represents state of vlan_id on physical network.""" - __tablename__ = 'network_states' - - physical_network = sa.Column(sa.String(64), nullable=False, - primary_key=True) - vlan_id = sa.Column(sa.Integer, nullable=False, primary_key=True, - autoincrement=False) - allocated = sa.Column(sa.Boolean, nullable=False) - - def __init__(self, physical_network, vlan_id): - self.physical_network = physical_network - self.vlan_id = vlan_id - self.allocated = False - - def __repr__(self): - return "" % (self.physical_network, - self.vlan_id, self.allocated) - - -class NetworkBinding(model_base.BASEV2): - """Represents binding of virtual network to physical network and vlan.""" - __tablename__ = 'network_bindings' - - network_id = sa.Column(sa.String(36), - sa.ForeignKey('networks.id', ondelete="CASCADE"), - primary_key=True) - physical_network = sa.Column(sa.String(64)) - vlan_id = sa.Column(sa.Integer, nullable=False) - - def __init__(self, network_id, physical_network, vlan_id): - self.network_id = network_id - self.physical_network = physical_network - self.vlan_id = vlan_id - - def __repr__(self): - return "" % (self.network_id, - self.physical_network, - self.vlan_id) diff --git a/neutron/plugins/linuxbridge/lb_neutron_plugin.py b/neutron/plugins/linuxbridge/lb_neutron_plugin.py deleted file mode 100644 index 412275d24..000000000 --- a/neutron/plugins/linuxbridge/lb_neutron_plugin.py +++ /dev/null @@ -1,530 +0,0 @@ -# Copyright (c) 2012 OpenStack Foundation. -# -# 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. - -import sys - -from oslo.config import cfg - -from neutron.agent import securitygroups_rpc as sg_rpc -from neutron.api.rpc.agentnotifiers import dhcp_rpc_agent_api -from neutron.api.rpc.agentnotifiers import l3_rpc_agent_api -from neutron.api.v2 import attributes -from neutron.common import constants as q_const -from neutron.common import exceptions as n_exc -from neutron.common import rpc_compat -from neutron.common import topics -from neutron.common import utils -from neutron.db import agents_db -from neutron.db import agentschedulers_db -from neutron.db import api as db_api -from neutron.db import db_base_plugin_v2 -from neutron.db import dhcp_rpc_base -from neutron.db import external_net_db -from neutron.db import extraroute_db -from neutron.db import l3_agentschedulers_db -from neutron.db import l3_gwmode_db -from neutron.db import l3_rpc_base -from neutron.db import portbindings_db -from neutron.db import quota_db # noqa -from neutron.db import securitygroups_rpc_base as sg_db_rpc -from neutron.extensions import portbindings -from neutron.extensions import providernet as provider -from neutron import manager -from neutron.openstack.common import importutils -from neutron.openstack.common import log as logging -from neutron.plugins.common import constants as svc_constants -from neutron.plugins.common import utils as plugin_utils -from neutron.plugins.linuxbridge.common import constants -from neutron.plugins.linuxbridge.db import l2network_db_v2 as db - - -LOG = logging.getLogger(__name__) - - -class LinuxBridgeRpcCallbacks(rpc_compat.RpcCallback, - dhcp_rpc_base.DhcpRpcCallbackMixin, - l3_rpc_base.L3RpcCallbackMixin, - sg_db_rpc.SecurityGroupServerRpcCallbackMixin - ): - - # history - # 1.1 Support Security Group RPC - RPC_API_VERSION = '1.1' - # Device names start with "tap" - TAP_PREFIX_LEN = 3 - - @classmethod - def get_port_from_device(cls, device): - port = db.get_port_from_device(device[cls.TAP_PREFIX_LEN:]) - if port: - port['device'] = device - return port - - def get_device_details(self, rpc_context, **kwargs): - """Agent requests device details.""" - agent_id = kwargs.get('agent_id') - device = kwargs.get('device') - LOG.debug(_("Device %(device)s details requested from %(agent_id)s"), - {'device': device, 'agent_id': agent_id}) - port = self.get_port_from_device(device) - if port: - binding = db.get_network_binding(db_api.get_session(), - port['network_id']) - (network_type, - segmentation_id) = constants.interpret_vlan_id(binding.vlan_id) - entry = {'device': device, - 'network_type': network_type, - 'physical_network': binding.physical_network, - 'segmentation_id': segmentation_id, - 'network_id': port['network_id'], - 'port_id': port['id'], - 'admin_state_up': port['admin_state_up']} - if cfg.CONF.AGENT.rpc_support_old_agents: - entry['vlan_id'] = binding.vlan_id - new_status = (q_const.PORT_STATUS_ACTIVE if port['admin_state_up'] - else q_const.PORT_STATUS_DOWN) - if port['status'] != new_status: - db.set_port_status(port['id'], new_status) - else: - entry = {'device': device} - LOG.debug(_("%s can not be found in database"), device) - return entry - - def update_device_down(self, rpc_context, **kwargs): - """Device no longer exists on agent.""" - # TODO(garyk) - live migration and port status - agent_id = kwargs.get('agent_id') - device = kwargs.get('device') - host = kwargs.get('host') - port = self.get_port_from_device(device) - LOG.debug(_("Device %(device)s no longer exists on %(agent_id)s"), - {'device': device, 'agent_id': agent_id}) - plugin = manager.NeutronManager.get_plugin() - if port: - entry = {'device': device, - 'exists': True} - if (host and not - plugin.get_port_host(rpc_context, port['id']) == host): - LOG.debug(_("Device %(device)s not bound to the" - " agent host %(host)s"), - {'device': device, 'host': host}) - elif port['status'] != q_const.PORT_STATUS_DOWN: - # Set port status to DOWN - db.set_port_status(port['id'], q_const.PORT_STATUS_DOWN) - else: - entry = {'device': device, - 'exists': False} - LOG.debug(_("%s can not be found in database"), device) - return entry - - def update_device_up(self, rpc_context, **kwargs): - """Device is up on agent.""" - agent_id = kwargs.get('agent_id') - device = kwargs.get('device') - host = kwargs.get('host') - port = self.get_port_from_device(device) - LOG.debug(_("Device %(device)s up on %(agent_id)s"), - {'device': device, 'agent_id': agent_id}) - plugin = manager.NeutronManager.get_plugin() - if port: - if (host and - not plugin.get_port_host(rpc_context, port['id']) == host): - LOG.debug(_("Device %(device)s not bound to the" - " agent host %(host)s"), - {'device': device, 'host': host}) - return - elif port['status'] != q_const.PORT_STATUS_ACTIVE: - db.set_port_status(port['id'], - q_const.PORT_STATUS_ACTIVE) - else: - LOG.debug(_("%s can not be found in database"), device) - - -class AgentNotifierApi(rpc_compat.RpcProxy, - sg_rpc.SecurityGroupAgentRpcApiMixin): - '''Agent side of the linux bridge rpc API. - - API version history: - 1.0 - Initial version. - 1.1 - Added get_active_networks_info, create_dhcp_port, - and update_dhcp_port methods. - - - ''' - - BASE_RPC_API_VERSION = '1.1' - - def __init__(self, topic): - super(AgentNotifierApi, self).__init__( - topic=topic, default_version=self.BASE_RPC_API_VERSION) - self.topic = topic - self.topic_network_delete = topics.get_topic_name(topic, - topics.NETWORK, - topics.DELETE) - self.topic_port_update = topics.get_topic_name(topic, - topics.PORT, - topics.UPDATE) - - def network_delete(self, context, network_id): - self.fanout_cast(context, - self.make_msg('network_delete', - network_id=network_id), - topic=self.topic_network_delete) - - def port_update(self, context, port, physical_network, vlan_id): - network_type, segmentation_id = constants.interpret_vlan_id(vlan_id) - kwargs = {'port': port, - 'network_type': network_type, - 'physical_network': physical_network, - 'segmentation_id': segmentation_id} - if cfg.CONF.AGENT.rpc_support_old_agents: - kwargs['vlan_id'] = vlan_id - msg = self.make_msg('port_update', **kwargs) - self.fanout_cast(context, msg, - topic=self.topic_port_update) - - -class LinuxBridgePluginV2(db_base_plugin_v2.NeutronDbPluginV2, - external_net_db.External_net_db_mixin, - extraroute_db.ExtraRoute_db_mixin, - l3_gwmode_db.L3_NAT_db_mixin, - sg_db_rpc.SecurityGroupServerRpcMixin, - l3_agentschedulers_db.L3AgentSchedulerDbMixin, - agentschedulers_db.DhcpAgentSchedulerDbMixin, - portbindings_db.PortBindingMixin): - """Implement the Neutron abstractions using Linux bridging. - - A new VLAN is created for each network. An agent is relied upon - to perform the actual Linux bridge configuration on each host. - - The provider extension is also supported. As discussed in - https://bugs.launchpad.net/neutron/+bug/1023156, this class could - be simplified, and filtering on extended attributes could be - handled, by adding support for extended attributes to the - NeutronDbPluginV2 base class. When that occurs, this class should - be updated to take advantage of it. - - The port binding extension enables an external application relay - information to and from the plugin. - """ - - # This attribute specifies whether the plugin supports or not - # bulk/pagination/sorting operations. Name mangling is used in - # order to ensure it is qualified by class - __native_bulk_support = True - __native_pagination_support = True - __native_sorting_support = True - - _supported_extension_aliases = ["provider", "external-net", "router", - "ext-gw-mode", "binding", "quotas", - "security-group", "agent", "extraroute", - "l3_agent_scheduler", - "dhcp_agent_scheduler"] - - @property - def supported_extension_aliases(self): - if not hasattr(self, '_aliases'): - aliases = self._supported_extension_aliases[:] - sg_rpc.disable_security_group_extension_by_config(aliases) - self._aliases = aliases - return self._aliases - - def __init__(self): - super(LinuxBridgePluginV2, self).__init__() - self.base_binding_dict = { - portbindings.VIF_TYPE: portbindings.VIF_TYPE_BRIDGE, - portbindings.VIF_DETAILS: { - # TODO(rkukura): Replace with new VIF security details - portbindings.CAP_PORT_FILTER: - 'security-group' in self.supported_extension_aliases}} - self._parse_network_vlan_ranges() - db.sync_network_states(self.network_vlan_ranges) - self.tenant_network_type = cfg.CONF.VLANS.tenant_network_type - if self.tenant_network_type not in [svc_constants.TYPE_LOCAL, - svc_constants.TYPE_VLAN, - svc_constants.TYPE_NONE]: - LOG.error(_("Invalid tenant_network_type: %s. " - "Service terminated!"), - self.tenant_network_type) - sys.exit(1) - self._setup_rpc() - self.network_scheduler = importutils.import_object( - cfg.CONF.network_scheduler_driver - ) - self.router_scheduler = importutils.import_object( - cfg.CONF.router_scheduler_driver - ) - LOG.debug(_("Linux Bridge Plugin initialization complete")) - - def _setup_rpc(self): - # RPC support - self.service_topics = {svc_constants.CORE: topics.PLUGIN, - svc_constants.L3_ROUTER_NAT: topics.L3PLUGIN} - self.conn = rpc_compat.create_connection(new=True) - self.endpoints = [LinuxBridgeRpcCallbacks(), - agents_db.AgentExtRpcCallback()] - for svc_topic in self.service_topics.values(): - self.conn.create_consumer(svc_topic, self.endpoints, fanout=False) - # Consume from all consumers in threads - self.conn.consume_in_threads() - self.notifier = AgentNotifierApi(topics.AGENT) - self.agent_notifiers[q_const.AGENT_TYPE_DHCP] = ( - dhcp_rpc_agent_api.DhcpAgentNotifyAPI() - ) - self.agent_notifiers[q_const.AGENT_TYPE_L3] = ( - l3_rpc_agent_api.L3AgentNotifyAPI() - ) - - def _parse_network_vlan_ranges(self): - try: - self.network_vlan_ranges = plugin_utils.parse_network_vlan_ranges( - cfg.CONF.VLANS.network_vlan_ranges) - except Exception as ex: - LOG.error(_("%s. Agent terminated!"), ex) - sys.exit(1) - LOG.info(_("Network VLAN ranges: %s"), self.network_vlan_ranges) - - def _add_network_vlan_range(self, physical_network, vlan_min, vlan_max): - self._add_network(physical_network) - self.network_vlan_ranges[physical_network].append((vlan_min, vlan_max)) - - def _add_network(self, physical_network): - if physical_network not in self.network_vlan_ranges: - self.network_vlan_ranges[physical_network] = [] - - def _extend_network_dict_provider(self, context, network): - binding = db.get_network_binding(context.session, network['id']) - if binding.vlan_id == constants.FLAT_VLAN_ID: - network[provider.NETWORK_TYPE] = svc_constants.TYPE_FLAT - network[provider.PHYSICAL_NETWORK] = binding.physical_network - network[provider.SEGMENTATION_ID] = None - elif binding.vlan_id == constants.LOCAL_VLAN_ID: - network[provider.NETWORK_TYPE] = svc_constants.TYPE_LOCAL - network[provider.PHYSICAL_NETWORK] = None - network[provider.SEGMENTATION_ID] = None - else: - network[provider.NETWORK_TYPE] = svc_constants.TYPE_VLAN - network[provider.PHYSICAL_NETWORK] = binding.physical_network - network[provider.SEGMENTATION_ID] = binding.vlan_id - - def _process_provider_create(self, context, attrs): - network_type = attrs.get(provider.NETWORK_TYPE) - physical_network = attrs.get(provider.PHYSICAL_NETWORK) - segmentation_id = attrs.get(provider.SEGMENTATION_ID) - - network_type_set = attributes.is_attr_set(network_type) - physical_network_set = attributes.is_attr_set(physical_network) - segmentation_id_set = attributes.is_attr_set(segmentation_id) - - if not (network_type_set or physical_network_set or - segmentation_id_set): - return (None, None, None) - - if not network_type_set: - msg = _("provider:network_type required") - raise n_exc.InvalidInput(error_message=msg) - elif network_type == svc_constants.TYPE_FLAT: - if segmentation_id_set: - msg = _("provider:segmentation_id specified for flat network") - raise n_exc.InvalidInput(error_message=msg) - else: - segmentation_id = constants.FLAT_VLAN_ID - elif network_type == svc_constants.TYPE_VLAN: - if not segmentation_id_set: - msg = _("provider:segmentation_id required") - raise n_exc.InvalidInput(error_message=msg) - if not utils.is_valid_vlan_tag(segmentation_id): - msg = (_("provider:segmentation_id out of range " - "(%(min_id)s through %(max_id)s)") % - {'min_id': q_const.MIN_VLAN_TAG, - 'max_id': q_const.MAX_VLAN_TAG}) - raise n_exc.InvalidInput(error_message=msg) - elif network_type == svc_constants.TYPE_LOCAL: - if physical_network_set: - msg = _("provider:physical_network specified for local " - "network") - raise n_exc.InvalidInput(error_message=msg) - else: - physical_network = None - if segmentation_id_set: - msg = _("provider:segmentation_id specified for local " - "network") - raise n_exc.InvalidInput(error_message=msg) - else: - segmentation_id = constants.LOCAL_VLAN_ID - else: - msg = _("provider:network_type %s not supported") % network_type - raise n_exc.InvalidInput(error_message=msg) - - if network_type in [svc_constants.TYPE_VLAN, svc_constants.TYPE_FLAT]: - if physical_network_set: - if physical_network not in self.network_vlan_ranges: - msg = (_("Unknown provider:physical_network %s") % - physical_network) - raise n_exc.InvalidInput(error_message=msg) - elif 'default' in self.network_vlan_ranges: - physical_network = 'default' - else: - msg = _("provider:physical_network required") - raise n_exc.InvalidInput(error_message=msg) - - return (network_type, physical_network, segmentation_id) - - def create_network(self, context, network): - (network_type, physical_network, - vlan_id) = self._process_provider_create(context, - network['network']) - - session = context.session - with session.begin(subtransactions=True): - #set up default security groups - tenant_id = self._get_tenant_id_for_create( - context, network['network']) - self._ensure_default_security_group(context, tenant_id) - - if not network_type: - # tenant network - network_type = self.tenant_network_type - if network_type == svc_constants.TYPE_NONE: - raise n_exc.TenantNetworksDisabled() - elif network_type == svc_constants.TYPE_VLAN: - physical_network, vlan_id = db.reserve_network(session) - else: # TYPE_LOCAL - vlan_id = constants.LOCAL_VLAN_ID - else: - # provider network - if network_type in [svc_constants.TYPE_VLAN, - svc_constants.TYPE_FLAT]: - db.reserve_specific_network(session, physical_network, - vlan_id) - # no reservation needed for TYPE_LOCAL - net = super(LinuxBridgePluginV2, self).create_network(context, - network) - db.add_network_binding(session, net['id'], - physical_network, vlan_id) - self._process_l3_create(context, net, network['network']) - self._extend_network_dict_provider(context, net) - # note - exception will rollback entire transaction - return net - - def update_network(self, context, id, network): - provider._raise_if_updates_provider_attributes(network['network']) - - session = context.session - with session.begin(subtransactions=True): - net = super(LinuxBridgePluginV2, self).update_network(context, id, - network) - self._process_l3_update(context, net, network['network']) - self._extend_network_dict_provider(context, net) - return net - - def delete_network(self, context, id): - session = context.session - with session.begin(subtransactions=True): - binding = db.get_network_binding(session, id) - self._process_l3_delete(context, id) - super(LinuxBridgePluginV2, self).delete_network(context, id) - if binding.vlan_id != constants.LOCAL_VLAN_ID: - db.release_network(session, binding.physical_network, - binding.vlan_id, self.network_vlan_ranges) - # the network_binding record is deleted via cascade from - # the network record, so explicit removal is not necessary - self.notifier.network_delete(context, id) - - def get_network(self, context, id, fields=None): - session = context.session - with session.begin(subtransactions=True): - net = super(LinuxBridgePluginV2, self).get_network(context, - id, None) - self._extend_network_dict_provider(context, net) - return self._fields(net, fields) - - def get_networks(self, context, filters=None, fields=None, - sorts=None, limit=None, marker=None, page_reverse=False): - session = context.session - with session.begin(subtransactions=True): - nets = super(LinuxBridgePluginV2, - self).get_networks(context, filters, None, sorts, - limit, marker, page_reverse) - for net in nets: - self._extend_network_dict_provider(context, net) - - return [self._fields(net, fields) for net in nets] - - def create_port(self, context, port): - session = context.session - port_data = port['port'] - with session.begin(subtransactions=True): - self._ensure_default_security_group_on_port(context, port) - sgids = self._get_security_groups_on_port(context, port) - # Set port status as 'DOWN'. This will be updated by agent - port['port']['status'] = q_const.PORT_STATUS_DOWN - - port = super(LinuxBridgePluginV2, - self).create_port(context, port) - self._process_portbindings_create_and_update(context, - port_data, - port) - self._process_port_create_security_group( - context, port, sgids) - self.notify_security_groups_member_updated(context, port) - return port - - def update_port(self, context, id, port): - original_port = self.get_port(context, id) - session = context.session - need_port_update_notify = False - - with session.begin(subtransactions=True): - updated_port = super(LinuxBridgePluginV2, self).update_port( - context, id, port) - self._process_portbindings_create_and_update(context, - port['port'], - updated_port) - need_port_update_notify = self.update_security_group_on_port( - context, id, port, original_port, updated_port) - - need_port_update_notify |= self.is_security_group_member_updated( - context, original_port, updated_port) - - if original_port['admin_state_up'] != updated_port['admin_state_up']: - need_port_update_notify = True - - if need_port_update_notify: - self._notify_port_updated(context, updated_port) - return updated_port - - def delete_port(self, context, id, l3_port_check=True): - - # if needed, check to see if this is a port owned by - # and l3-router. If so, we should prevent deletion. - if l3_port_check: - self.prevent_l3_port_deletion(context, id) - - session = context.session - with session.begin(subtransactions=True): - self.disassociate_floatingips(context, id) - port = self.get_port(context, id) - self._delete_port_security_group_bindings(context, id) - super(LinuxBridgePluginV2, self).delete_port(context, id) - - self.notify_security_groups_member_updated(context, port) - - def _notify_port_updated(self, context, port): - binding = db.get_network_binding(context.session, - port['network_id']) - self.notifier.port_update(context, port, - binding.physical_network, - binding.vlan_id) diff --git a/neutron/plugins/metaplugin/README b/neutron/plugins/metaplugin/README deleted file mode 100644 index 8dbc47756..000000000 --- a/neutron/plugins/metaplugin/README +++ /dev/null @@ -1,92 +0,0 @@ -# -- Background - -This plugin supports multiple plugin at same time. This plugin is for L3 connectivility -between networks which are realized by different plugins.This plugin adds new attributes 'flavor:network' and 'flavor:router". -flavor:network corresponds to specific l2 plugin ( flavor-plugin mapping could be configurable by plugin_list config. -flavor:router corresponds to specific l3 plugin ( flavor-plugin mapping could be configurable by l3_plugin_list config. Note that Metaplugin can provide l3 functionaliteis for l2 plugin which didn't support l3 extension yet. -This plugin also support extensions. We can map extension to plugin by using extension_map config. - -[database] -# This line MUST be changed to actually run the plugin. -# Example: -# connection = mysql://root:nova@127.0.0.1:3306/ovs_neutron -# Replace 127.0.0.1 above with the IP address of the database used by the -# main neutron server. (Leave it as is if the database runs on this host.) -connection = mysql://root:password@localhost/neutron_metaplugin?charset=utf8 - -# Database reconnection retry times - in event connectivity is lost -# set to -1 implgies an infinite retry count -# max_retries = 10 -# Database reconnection interval in seconds - in event connectivity is lost -retry_interval = 2 - -[meta] -## This is list of flavor:neutron_plugins -# extension method is used in the order of this list -plugin_list= 'openvswitch:neutron.plugins.openvswitch.ovs_neutron_plugin.OVSneutronPluginV2,linuxbridge:neutron.plugins.linuxbridge.lb_neutron_plugin.LinuxBridgePluginV2' -# plugin for l3 -l3_plugin_list= 'openvswitch:neutron.plugins.openvswitch.ovs_neutron_plugin.OVSneutronPluginV2,linuxbridge:neutron.plugins.linuxbridge.lb_neutron_plugin.LinuxBridgePluginV2' - -# Default value of flavor -default_flavor = 'openvswitch' -# Default value for l3 -default_l3_flavor = 'openvswitch' - -# supported extensions -supported_extension_aliases = 'providernet' -# specific method map for each flavor to extensions -extension_map = 'get_port_stats:nvp' - -# -- BridgeDriver Configration -# In order to use metaplugin, you should use MetaDriver. Following configation is needed. - -[DEFAULT] -# Meta Plugin -# Mapping between flavor and driver -meta_flavor_driver_mappings = openvswitch:neutron.agent.linux.interface.OVSInterfaceDriver, linuxbridge:neutron.agent.linux.interface.BridgeInterfaceDriver -# interface driver for MetaPlugin -interface_driver = neutron.agent.linux.interface.MetaInterfaceDriver - -[proxy] -auth_url = http://10.0.0.1:35357/v2.0 -auth_region = RegionOne -admin_tenant_name = service -admin_user = neutron -admin_password = password - - -# -- Agent -Agents for Metaplugin are in neutron/plugins/metaplugin/agent -linuxbridge_neutron_agent and ovs_neutron_agent is available. - -# -- Extensions - -- flavor -MetaPlugin supports flavor and provider net extension. -Metaplugin select plugin_list using flavor. -One plugin may use multiple flavor value. If the plugin support flavor, it may provide -multiple flavor of network. - -- Attribute extension -Each plugin can use attribute extension such as provider_net, if you specify that in supported_extension_aliases. - -- providernet -Vlan ID range of each plugin should be different, since Metaplugin dose not manage that. - -#- limitations - -Basically, All plugin should inherit NeutronDbPluginV2. -Metaplugin assumes all plugin share same Database especially for IPAM part in NeutronV2 API. -You can use another plugin if you use ProxyPluginV2, which proxies request to the another neutron server. - -Example flavor configration for ProxyPluginV2 - -meta_flavor_driver_mappings = "openvswitch:neutron.agent.linux.interface.OVSInterfaceDriver,proxy:neutron.plugins.metaplugin.proxy_neutron_plugin.ProxyPluginV2" - -- Limited L3 support -In folsom version, l3 is an extension. There is no way to extend exntension attributes. -so you can set flavor:router value but you can't get flavor:router value in API output. -L3 agent dont's support flavor:router. - - - diff --git a/neutron/plugins/metaplugin/__init__.py b/neutron/plugins/metaplugin/__init__.py deleted file mode 100644 index d8bce7745..000000000 --- a/neutron/plugins/metaplugin/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012, Nachi Ueno, NTT MCL, Inc. -# 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. diff --git a/neutron/plugins/metaplugin/common/__init__.py b/neutron/plugins/metaplugin/common/__init__.py deleted file mode 100644 index d8bce7745..000000000 --- a/neutron/plugins/metaplugin/common/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012, Nachi Ueno, NTT MCL, Inc. -# 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. diff --git a/neutron/plugins/metaplugin/common/config.py b/neutron/plugins/metaplugin/common/config.py deleted file mode 100644 index 26978d71b..000000000 --- a/neutron/plugins/metaplugin/common/config.py +++ /dev/null @@ -1,80 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012, Nachi Ueno, NTT MCL, Inc. -# 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 oslo.config import cfg - - -meta_plugin_opts = [ - cfg.StrOpt( - 'plugin_list', - default='', - help=_("Comma separated list of flavor:neutron_plugin for " - "plugins to load. Extension method is searched in the " - "list order and the first one is used.")), - cfg.StrOpt( - 'l3_plugin_list', - default='', - help=_("Comma separated list of flavor:neutron_plugin for L3 " - "service plugins to load. This is intended for specifying " - "L2 plugins which support L3 functions. If you use a router " - "service plugin, set this blank.")), - cfg.StrOpt( - 'default_flavor', - default='', - help=_("Default flavor to use, when flavor:network is not " - "specified at network creation.")), - cfg.StrOpt( - 'default_l3_flavor', - default='', - help=_("Default L3 flavor to use, when flavor:router is not " - "specified at router creation. Ignored if 'l3_plugin_list' " - "is blank.")), - cfg.StrOpt( - 'supported_extension_aliases', - default='', - help=_("Comma separated list of supported extension aliases.")), - cfg.StrOpt( - 'extension_map', - default='', - help=_("Comma separated list of method:flavor to select specific " - "plugin for a method. This has priority over method search " - "order based on 'plugin_list'.")), - cfg.StrOpt( - 'rpc_flavor', - default='', - help=_("Specifies flavor for plugin to handle 'q-plugin' RPC " - "requests.")), -] - -proxy_plugin_opts = [ - cfg.StrOpt('admin_user', - help=_("Admin user")), - cfg.StrOpt('admin_password', - help=_("Admin password"), - secret=True), - cfg.StrOpt('admin_tenant_name', - help=_("Admin tenant name")), - cfg.StrOpt('auth_url', - help=_("Authentication URL")), - cfg.StrOpt('auth_strategy', default='keystone', - help=_("The type of authentication to use")), - cfg.StrOpt('auth_region', - help=_("Authentication region")), -] - -cfg.CONF.register_opts(meta_plugin_opts, "META") -cfg.CONF.register_opts(proxy_plugin_opts, "PROXY") diff --git a/neutron/plugins/metaplugin/meta_db_v2.py b/neutron/plugins/metaplugin/meta_db_v2.py deleted file mode 100644 index 68c9055ff..000000000 --- a/neutron/plugins/metaplugin/meta_db_v2.py +++ /dev/null @@ -1,52 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012, Nachi Ueno, NTT MCL, Inc. -# 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 sqlalchemy.orm import exc - -from neutron.plugins.metaplugin import meta_models_v2 - - -def get_flavor_by_network(session, net_id): - try: - binding = (session.query(meta_models_v2.NetworkFlavor). - filter_by(network_id=net_id). - one()) - except exc.NoResultFound: - return None - return binding.flavor - - -def add_network_flavor_binding(session, flavor, net_id): - binding = meta_models_v2.NetworkFlavor(flavor=flavor, network_id=net_id) - session.add(binding) - return binding - - -def get_flavor_by_router(session, router_id): - try: - binding = (session.query(meta_models_v2.RouterFlavor). - filter_by(router_id=router_id). - one()) - except exc.NoResultFound: - return None - return binding.flavor - - -def add_router_flavor_binding(session, flavor, router_id): - binding = meta_models_v2.RouterFlavor(flavor=flavor, router_id=router_id) - session.add(binding) - return binding diff --git a/neutron/plugins/metaplugin/meta_models_v2.py b/neutron/plugins/metaplugin/meta_models_v2.py deleted file mode 100644 index 566d1d8d8..000000000 --- a/neutron/plugins/metaplugin/meta_models_v2.py +++ /dev/null @@ -1,43 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 -# -# Copyright 2012, Nachi Ueno, NTT MCL, Inc. -# 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. - -import sqlalchemy as sa -from sqlalchemy import Column, String - -from neutron.db import models_v2 - - -class NetworkFlavor(models_v2.model_base.BASEV2): - """Represents a binding of network_id to flavor.""" - flavor = Column(String(255)) - network_id = sa.Column(sa.String(36), sa.ForeignKey('networks.id', - ondelete="CASCADE"), - primary_key=True) - - def __repr__(self): - return "" % (self.flavor, self.network_id) - - -class RouterFlavor(models_v2.model_base.BASEV2): - """Represents a binding of router_id to flavor.""" - flavor = Column(String(255)) - router_id = sa.Column(sa.String(36), sa.ForeignKey('routers.id', - ondelete="CASCADE"), - primary_key=True) - - def __repr__(self): - return "" % (self.flavor, self.router_id) diff --git a/neutron/plugins/metaplugin/meta_neutron_plugin.py b/neutron/plugins/metaplugin/meta_neutron_plugin.py deleted file mode 100644 index 92a962846..000000000 --- a/neutron/plugins/metaplugin/meta_neutron_plugin.py +++ /dev/null @@ -1,419 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012, Nachi Ueno, NTT MCL, Inc. -# 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 oslo.config import cfg - -from neutron.common import exceptions as exc -from neutron.common import topics -from neutron import context as neutron_context -from neutron.db import api as db -from neutron.db import db_base_plugin_v2 -from neutron.db import external_net_db -from neutron.db import extraroute_db -from neutron.db import l3_db -from neutron.db import models_v2 -from neutron.extensions import flavor as ext_flavor -from neutron.openstack.common import importutils -from neutron.openstack.common import log as logging -from neutron.plugins.metaplugin.common import config # noqa -from neutron.plugins.metaplugin import meta_db_v2 -from neutron.plugins.metaplugin import meta_models_v2 - - -LOG = logging.getLogger(__name__) - - -# Hooks used to select records which belong a target plugin. -def _meta_network_model_hook(context, original_model, query): - return query.outerjoin(meta_models_v2.NetworkFlavor, - meta_models_v2.NetworkFlavor.network_id == - models_v2.Network.id) - - -def _meta_port_model_hook(context, original_model, query): - return query.join(meta_models_v2.NetworkFlavor, - meta_models_v2.NetworkFlavor.network_id == - models_v2.Port.network_id) - - -def _meta_flavor_filter_hook(query, filters): - if ext_flavor.FLAVOR_NETWORK in filters: - return query.filter(meta_models_v2.NetworkFlavor.flavor == - filters[ext_flavor.FLAVOR_NETWORK][0]) - return query - - -# Metaplugin Exceptions -class FlavorNotFound(exc.NotFound): - message = _("Flavor %(flavor)s could not be found") - - -class FaildToAddFlavorBinding(exc.NeutronException): - message = _("Failed to add flavor binding") - - -class MetaPluginV2(db_base_plugin_v2.NeutronDbPluginV2, - external_net_db.External_net_db_mixin, - extraroute_db.ExtraRoute_db_mixin): - - def __init__(self, configfile=None): - super(MetaPluginV2, self).__init__() - LOG.debug(_("Start initializing metaplugin")) - self.supported_extension_aliases = ['flavor', 'external-net'] - if cfg.CONF.META.supported_extension_aliases: - cfg_aliases = cfg.CONF.META.supported_extension_aliases.split(',') - self.supported_extension_aliases += cfg_aliases - - # Ignore config option overapping - def _is_opt_registered(opts, opt): - if opt.dest in opts: - return True - else: - return False - - cfg._is_opt_registered = _is_opt_registered - - # Keep existing tables if multiple plugin use same table name. - db.model_base.NeutronBase.__table_args__ = {'keep_existing': True} - - self.plugins = {} - - plugin_list = [plugin_set.split(':') - for plugin_set - in cfg.CONF.META.plugin_list.split(',')] - self.rpc_flavor = cfg.CONF.META.rpc_flavor - topic_save = topics.PLUGIN - topic_fake = topic_save + '-metaplugin' - for flavor, plugin_provider in plugin_list: - # Rename topic used by a plugin other than rpc_flavor during - # loading the plugin instance if rpc_flavor is specified. - # This enforces the plugin specified by rpc_flavor is only - # consumer of 'q-plugin'. It is a bit tricky but there is no - # bad effect. - if self.rpc_flavor and self.rpc_flavor != flavor: - topics.PLUGIN = topic_fake - self.plugins[flavor] = self._load_plugin(plugin_provider) - topics.PLUGIN = topic_save - - self.l3_plugins = {} - if cfg.CONF.META.l3_plugin_list: - l3_plugin_list = [plugin_set.split(':') - for plugin_set - in cfg.CONF.META.l3_plugin_list.split(',')] - for flavor, plugin_provider in l3_plugin_list: - if flavor in self.plugins: - self.l3_plugins[flavor] = self.plugins[flavor] - else: - # For l3 only plugin - self.l3_plugins[flavor] = self._load_plugin( - plugin_provider) - - self.default_flavor = cfg.CONF.META.default_flavor - if self.default_flavor not in self.plugins: - raise exc.Invalid(_('default_flavor %s is not plugin list') % - self.default_flavor) - - if self.l3_plugins: - self.default_l3_flavor = cfg.CONF.META.default_l3_flavor - if self.default_l3_flavor not in self.l3_plugins: - raise exc.Invalid(_('default_l3_flavor %s is not plugin list') - % self.default_l3_flavor) - self.supported_extension_aliases += ['router', 'ext-gw-mode', - 'extraroute'] - - if self.rpc_flavor and self.rpc_flavor not in self.plugins: - raise exc.Invalid(_('rpc_flavor %s is not plugin list') % - self.rpc_flavor) - - self.extension_map = {} - if not cfg.CONF.META.extension_map == '': - extension_list = [method_set.split(':') - for method_set - in cfg.CONF.META.extension_map.split(',')] - for method_name, flavor in extension_list: - self.extension_map[method_name] = flavor - - # Register hooks. - # The hooks are applied for each target plugin instance when - # calling the base class to get networks/ports so that only records - # which belong to the plugin are selected. - #NOTE: Doing registration here (within __init__()) is to avoid - # registration when merely importing this file. This is only - # for running whole unit tests. - db_base_plugin_v2.NeutronDbPluginV2.register_model_query_hook( - models_v2.Network, - 'metaplugin_net', - _meta_network_model_hook, - None, - _meta_flavor_filter_hook) - db_base_plugin_v2.NeutronDbPluginV2.register_model_query_hook( - models_v2.Port, - 'metaplugin_port', - _meta_port_model_hook, - None, - _meta_flavor_filter_hook) - - def _load_plugin(self, plugin_provider): - LOG.debug(_("Plugin location: %s"), plugin_provider) - plugin_klass = importutils.import_class(plugin_provider) - return plugin_klass() - - def _get_plugin(self, flavor): - if flavor not in self.plugins: - raise FlavorNotFound(flavor=flavor) - return self.plugins[flavor] - - def _get_l3_plugin(self, flavor): - if flavor not in self.l3_plugins: - raise FlavorNotFound(flavor=flavor) - return self.l3_plugins[flavor] - - def __getattr__(self, key): - # At first, try to pickup extension command from extension_map - - if key in self.extension_map: - flavor = self.extension_map[key] - plugin = self._get_plugin(flavor) - if plugin and hasattr(plugin, key): - return getattr(plugin, key) - - # Second, try to match extension method in order of plugin list - for flavor, plugin in self.plugins.items(): - if hasattr(plugin, key): - return getattr(plugin, key) - - # if no plugin support the method, then raise - raise AttributeError - - def _extend_network_dict(self, context, network): - flavor = self._get_flavor_by_network_id(context, network['id']) - network[ext_flavor.FLAVOR_NETWORK] = flavor - - def start_rpc_listeners(self): - return self.plugins[self.rpc_flavor].start_rpc_listeners() - - def rpc_workers_supported(self): - #NOTE: If a plugin which supports multiple RPC workers is desired - # to handle RPC, rpc_flavor must be specified. - return (self.rpc_flavor and - self.plugins[self.rpc_flavor].rpc_workers_supported()) - - def create_network(self, context, network): - n = network['network'] - flavor = n.get(ext_flavor.FLAVOR_NETWORK) - if str(flavor) not in self.plugins: - flavor = self.default_flavor - plugin = self._get_plugin(flavor) - net = plugin.create_network(context, network) - LOG.debug(_("Created network: %(net_id)s with flavor " - "%(flavor)s"), {'net_id': net['id'], 'flavor': flavor}) - try: - meta_db_v2.add_network_flavor_binding(context.session, - flavor, str(net['id'])) - except Exception: - LOG.exception(_('Failed to add flavor bindings')) - plugin.delete_network(context, net['id']) - raise FaildToAddFlavorBinding() - - LOG.debug(_("Created network: %s"), net['id']) - self._extend_network_dict(context, net) - return net - - def update_network(self, context, id, network): - flavor = meta_db_v2.get_flavor_by_network(context.session, id) - plugin = self._get_plugin(flavor) - return plugin.update_network(context, id, network) - - def delete_network(self, context, id): - flavor = meta_db_v2.get_flavor_by_network(context.session, id) - plugin = self._get_plugin(flavor) - return plugin.delete_network(context, id) - - def get_network(self, context, id, fields=None): - flavor = meta_db_v2.get_flavor_by_network(context.session, id) - plugin = self._get_plugin(flavor) - net = plugin.get_network(context, id, fields) - net['id'] = id - if not fields or ext_flavor.FLAVOR_NETWORK in fields: - self._extend_network_dict(context, net) - if fields and 'id' not in fields: - del net['id'] - return net - - def get_networks(self, context, filters=None, fields=None): - nets = [] - for flavor, plugin in self.plugins.items(): - if (filters and ext_flavor.FLAVOR_NETWORK in filters and - not flavor in filters[ext_flavor.FLAVOR_NETWORK]): - continue - if filters: - #NOTE: copy each time since a target plugin may modify - # plugin_filters. - plugin_filters = filters.copy() - else: - plugin_filters = {} - plugin_filters[ext_flavor.FLAVOR_NETWORK] = [flavor] - plugin_nets = plugin.get_networks(context, plugin_filters, fields) - for net in plugin_nets: - if not fields or ext_flavor.FLAVOR_NETWORK in fields: - net[ext_flavor.FLAVOR_NETWORK] = flavor - nets.append(net) - return nets - - def _get_flavor_by_network_id(self, context, network_id): - return meta_db_v2.get_flavor_by_network(context.session, network_id) - - def _get_flavor_by_router_id(self, context, router_id): - return meta_db_v2.get_flavor_by_router(context.session, router_id) - - def _get_plugin_by_network_id(self, context, network_id): - flavor = self._get_flavor_by_network_id(context, network_id) - return self._get_plugin(flavor) - - def create_port(self, context, port): - p = port['port'] - if 'network_id' not in p: - raise exc.NotFound - plugin = self._get_plugin_by_network_id(context, p['network_id']) - return plugin.create_port(context, port) - - def update_port(self, context, id, port): - port_in_db = self._get_port(context, id) - plugin = self._get_plugin_by_network_id(context, - port_in_db['network_id']) - return plugin.update_port(context, id, port) - - def delete_port(self, context, id, l3_port_check=True): - port_in_db = self._get_port(context, id) - plugin = self._get_plugin_by_network_id(context, - port_in_db['network_id']) - return plugin.delete_port(context, id, l3_port_check) - - # This is necessary since there is a case that - # NeutronManager.get_plugin()._make_port_dict is called. - def _make_port_dict(self, port): - context = neutron_context.get_admin_context() - plugin = self._get_plugin_by_network_id(context, - port['network_id']) - return plugin._make_port_dict(port) - - def get_port(self, context, id, fields=None): - port_in_db = self._get_port(context, id) - plugin = self._get_plugin_by_network_id(context, - port_in_db['network_id']) - return plugin.get_port(context, id, fields) - - def get_ports(self, context, filters=None, fields=None): - all_ports = [] - for flavor, plugin in self.plugins.items(): - if filters: - #NOTE: copy each time since a target plugin may modify - # plugin_filters. - plugin_filters = filters.copy() - else: - plugin_filters = {} - plugin_filters[ext_flavor.FLAVOR_NETWORK] = [flavor] - ports = plugin.get_ports(context, plugin_filters, fields) - all_ports += ports - return all_ports - - def create_subnet(self, context, subnet): - s = subnet['subnet'] - if 'network_id' not in s: - raise exc.NotFound - plugin = self._get_plugin_by_network_id(context, - s['network_id']) - return plugin.create_subnet(context, subnet) - - def update_subnet(self, context, id, subnet): - s = self.get_subnet(context, id) - plugin = self._get_plugin_by_network_id(context, - s['network_id']) - return plugin.update_subnet(context, id, subnet) - - def delete_subnet(self, context, id): - s = self.get_subnet(context, id) - plugin = self._get_plugin_by_network_id(context, - s['network_id']) - return plugin.delete_subnet(context, id) - - def _extend_router_dict(self, context, router): - flavor = self._get_flavor_by_router_id(context, router['id']) - router[ext_flavor.FLAVOR_ROUTER] = flavor - - def create_router(self, context, router): - r = router['router'] - flavor = r.get(ext_flavor.FLAVOR_ROUTER) - if str(flavor) not in self.l3_plugins: - flavor = self.default_l3_flavor - plugin = self._get_l3_plugin(flavor) - r_in_db = plugin.create_router(context, router) - LOG.debug(_("Created router: %(router_id)s with flavor " - "%(flavor)s"), - {'router_id': r_in_db['id'], 'flavor': flavor}) - try: - meta_db_v2.add_router_flavor_binding(context.session, - flavor, str(r_in_db['id'])) - except Exception: - LOG.exception(_('Failed to add flavor bindings')) - plugin.delete_router(context, r_in_db['id']) - raise FaildToAddFlavorBinding() - - LOG.debug(_("Created router: %s"), r_in_db['id']) - self._extend_router_dict(context, r_in_db) - return r_in_db - - def update_router(self, context, id, router): - flavor = meta_db_v2.get_flavor_by_router(context.session, id) - plugin = self._get_l3_plugin(flavor) - return plugin.update_router(context, id, router) - - def delete_router(self, context, id): - flavor = meta_db_v2.get_flavor_by_router(context.session, id) - plugin = self._get_l3_plugin(flavor) - return plugin.delete_router(context, id) - - def get_router(self, context, id, fields=None): - flavor = meta_db_v2.get_flavor_by_router(context.session, id) - plugin = self._get_l3_plugin(flavor) - router = plugin.get_router(context, id, fields) - if not fields or ext_flavor.FLAVOR_ROUTER in fields: - self._extend_router_dict(context, router) - return router - - def get_routers_with_flavor(self, context, filters=None, - fields=None): - collection = self._model_query(context, l3_db.Router) - r_model = meta_models_v2.RouterFlavor - collection = collection.join(r_model, - l3_db.Router.id == r_model.router_id) - if filters: - for key, value in filters.iteritems(): - if key == ext_flavor.FLAVOR_ROUTER: - column = meta_models_v2.RouterFlavor.flavor - else: - column = getattr(l3_db.Router, key, None) - if column: - collection = collection.filter(column.in_(value)) - return [self._make_router_dict(c, fields) for c in collection] - - def get_routers(self, context, filters=None, fields=None): - routers = self.get_routers_with_flavor(context, filters, - None) - return [self.get_router(context, router['id'], - fields) - for router in routers] diff --git a/neutron/plugins/metaplugin/proxy_neutron_plugin.py b/neutron/plugins/metaplugin/proxy_neutron_plugin.py deleted file mode 100644 index 61cc34026..000000000 --- a/neutron/plugins/metaplugin/proxy_neutron_plugin.py +++ /dev/null @@ -1,136 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright 2012, Nachi Ueno, NTT MCL, Inc. -# 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 oslo.config import cfg - -from neutron.db import db_base_plugin_v2 -from neutron.db import external_net_db -from neutron.db import l3_db -from neutron.openstack.common import log as logging -from neutronclient.common import exceptions -from neutronclient.v2_0 import client - - -LOG = logging.getLogger(__name__) - - -class ProxyPluginV2(db_base_plugin_v2.NeutronDbPluginV2, - external_net_db.External_net_db_mixin, - l3_db.L3_NAT_db_mixin): - supported_extension_aliases = ["external-net", "router"] - - def __init__(self, configfile=None): - super(ProxyPluginV2, self).__init__() - self.neutron = client.Client( - username=cfg.CONF.PROXY.admin_user, - password=cfg.CONF.PROXY.admin_password, - tenant_name=cfg.CONF.PROXY.admin_tenant_name, - auth_url=cfg.CONF.PROXY.auth_url, - auth_strategy=cfg.CONF.PROXY.auth_strategy, - region_name=cfg.CONF.PROXY.auth_region - ) - - def _get_client(self): - return self.neutron - - def create_subnet(self, context, subnet): - subnet_remote = self._get_client().create_subnet(subnet) - subnet['subnet']['id'] = subnet_remote['id'] - tenant_id = self._get_tenant_id_for_create(context, subnet['subnet']) - subnet['subnet']['tenant_id'] = tenant_id - try: - subnet_in_db = super(ProxyPluginV2, self).create_subnet( - context, subnet) - except Exception: - self._get_client().delete_subnet(subnet_remote['id']) - return subnet_in_db - - def update_subnet(self, context, id, subnet): - subnet_in_db = super(ProxyPluginV2, self).update_subnet( - context, id, subnet) - try: - self._get_client().update_subnet(id, subnet) - except Exception as e: - LOG.error(_("Update subnet failed: %s"), e) - return subnet_in_db - - def delete_subnet(self, context, id): - try: - self._get_client().delete_subnet(id) - except exceptions.NotFound: - LOG.warn(_("Subnet in remote have already deleted")) - return super(ProxyPluginV2, self).delete_subnet(context, id) - - def create_network(self, context, network): - network_remote = self._get_client().create_network(network) - network['network']['id'] = network_remote['id'] - tenant_id = self._get_tenant_id_for_create(context, network['network']) - network['network']['tenant_id'] = tenant_id - try: - network_in_db = super(ProxyPluginV2, self).create_network( - context, network) - except Exception: - self._get_client().delete_network(network_remote['id']) - return network_in_db - - def update_network(self, context, id, network): - network_in_db = super(ProxyPluginV2, self).update_network( - context, id, network) - try: - self._get_client().update_network(id, network) - except Exception as e: - LOG.error(_("Update network failed: %s"), e) - return network_in_db - - def delete_network(self, context, id): - try: - self._get_client().delete_network(id) - except exceptions.NetworkNotFoundClient: - LOG.warn(_("Network in remote have already deleted")) - return super(ProxyPluginV2, self).delete_network(context, id) - - def create_port(self, context, port): - port_remote = self._get_client().create_port(port) - port['port']['id'] = port_remote['id'] - tenant_id = self._get_tenant_id_for_create(context, port['port']) - port['port']['tenant_id'] = tenant_id - try: - port_in_db = super(ProxyPluginV2, self).create_port( - context, port) - except Exception: - self._get_client().delete_port(port_remote['id']) - return port_in_db - - def update_port(self, context, id, port): - port_in_db = super(ProxyPluginV2, self).update_port( - context, id, port) - try: - self._get_client().update_port(id, port) - except Exception as e: - LOG.error(_("Update port failed: %s"), e) - return port_in_db - - def delete_port(self, context, id, l3_port_check=True): - if l3_port_check: - self.prevent_l3_port_deletion(context, id) - self.disassociate_floatingips(context, id) - - try: - self._get_client().delete_port(id) - except exceptions.PortNotFoundClient: - LOG.warn(_("Port in remote have already deleted")) - return super(ProxyPluginV2, self).delete_port(context, id) diff --git a/neutron/plugins/midonet/__init__.py b/neutron/plugins/midonet/__init__.py deleted file mode 100644 index 439ff6594..000000000 --- a/neutron/plugins/midonet/__init__.py +++ /dev/null @@ -1,17 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (C) 2012 Midokura Japan K.K. -# Copyright (C) 2013 Midokura PTE LTD -# 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. diff --git a/neutron/plugins/midonet/agent/__init__.py b/neutron/plugins/midonet/agent/__init__.py deleted file mode 100644 index 9fddc1976..000000000 --- a/neutron/plugins/midonet/agent/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (C) 2013 Midokura PTE LTD -# 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. diff --git a/neutron/plugins/midonet/agent/midonet_driver.py b/neutron/plugins/midonet/agent/midonet_driver.py deleted file mode 100644 index ada98a3d1..000000000 --- a/neutron/plugins/midonet/agent/midonet_driver.py +++ /dev/null @@ -1,52 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (C) 2013 Midokura PTE LTD -# 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: Rossella Sblendido, Midokura Japan KK -# @author: Tomoe Sugihara, Midokura Japan KK -# @author: Ryu Ishimoto, Midokura Japan KK - -from neutron.agent.linux import dhcp -from neutron.openstack.common import log as logging -from neutron.plugins.midonet.common import config # noqa - -LOG = logging.getLogger(__name__) - - -class DhcpNoOpDriver(dhcp.DhcpLocalProcess): - - @classmethod - def existing_dhcp_networks(cls, conf, root_helper): - """Return a list of existing networks ids that we have configs for.""" - return [] - - @classmethod - def check_version(cls): - """Execute version checks on DHCP server.""" - return float(1.0) - - def disable(self, retain_port=False): - """Disable DHCP for this network.""" - if not retain_port: - self.device_manager.destroy(self.network, self.interface_name) - self._remove_config_files() - - def reload_allocations(self): - """Force the DHCP server to reload the assignment database.""" - pass - - def spawn_process(self): - pass diff --git a/neutron/plugins/midonet/common/__init__.py b/neutron/plugins/midonet/common/__init__.py deleted file mode 100644 index 9fddc1976..000000000 --- a/neutron/plugins/midonet/common/__init__.py +++ /dev/null @@ -1,16 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (C) 2013 Midokura PTE LTD -# 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. diff --git a/neutron/plugins/midonet/common/config.py b/neutron/plugins/midonet/common/config.py deleted file mode 100644 index 924474f5b..000000000 --- a/neutron/plugins/midonet/common/config.py +++ /dev/null @@ -1,46 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (C) 2012 Midokura Japan K.K. -# Copyright (C) 2013 Midokura PTE LTD -# 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: Tomoe Sugihara, Midokura Japan KK - -from oslo.config import cfg - -midonet_opts = [ - cfg.StrOpt('midonet_uri', default='http://localhost:8080/midonet-api', - help=_('MidoNet API server URI.')), - cfg.StrOpt('username', default='admin', - help=_('MidoNet admin username.')), - cfg.StrOpt('password', default='passw0rd', - secret=True, - help=_('MidoNet admin password.')), - cfg.StrOpt('project_id', - default='77777777-7777-7777-7777-777777777777', - help=_('ID of the project that MidoNet admin user' - 'belongs to.')), - cfg.StrOpt('provider_router_id', - help=_('Virtual provider router ID.')), - cfg.StrOpt('mode', - default='dev', - help=_('Operational mode. Internal dev use only.')), - cfg.StrOpt('midonet_host_uuid_path', - default='/etc/midolman/host_uuid.properties', - help=_('Path to midonet host uuid file')) -] - - -cfg.CONF.register_opts(midonet_opts, "MIDONET") diff --git a/neutron/plugins/midonet/common/net_util.py b/neutron/plugins/midonet/common/net_util.py deleted file mode 100644 index 884048675..000000000 --- a/neutron/plugins/midonet/common/net_util.py +++ /dev/null @@ -1,68 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (C) 2013 Midokura PTE LTD -# 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: Ryu Ishimoto, Midokura Japan KK - - -from neutron.common import constants - - -def subnet_str(cidr): - """Convert the cidr string to x.x.x.x_y format - - :param cidr: CIDR in x.x.x.x/y format - """ - if cidr is None: - return None - return cidr.replace("/", "_") - - -def net_addr(addr): - """Get network address prefix and length from a given address.""" - if addr is None: - return (None, None) - nw_addr, nw_len = addr.split('/') - nw_len = int(nw_len) - return nw_addr, nw_len - - -def get_ethertype_value(ethertype): - """Convert string representation of ethertype to the numerical.""" - if ethertype is None: - return None - mapping = { - 'ipv4': 0x0800, - 'ipv6': 0x86DD, - 'arp': 0x806 - } - return mapping.get(ethertype.lower()) - - -def get_protocol_value(protocol): - """Convert string representation of protocol to the numerical.""" - if protocol is None: - return None - - if isinstance(protocol, int): - return protocol - - mapping = { - constants.PROTO_NAME_TCP: constants.PROTO_NUM_TCP, - constants.PROTO_NAME_UDP: constants.PROTO_NUM_UDP, - constants.PROTO_NAME_ICMP: constants.PROTO_NUM_ICMP - } - return mapping.get(protocol.lower()) diff --git a/neutron/plugins/midonet/midonet_lib.py b/neutron/plugins/midonet/midonet_lib.py deleted file mode 100644 index 74d2bae6a..000000000 --- a/neutron/plugins/midonet/midonet_lib.py +++ /dev/null @@ -1,696 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (C) 2012 Midokura Japan K.K. -# Copyright (C) 2013 Midokura PTE LTD -# 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: Tomoe Sugihara, Midokura Japan KK -# @author: Ryu Ishimoto, Midokura Japan KK -# @author: Rossella Sblendido, Midokura Japan KK -# @author: Duarte Nunes, Midokura Japan KK - -from midonetclient import exc -from webob import exc as w_exc - -from neutron.common import exceptions as n_exc -from neutron.openstack.common import log as logging -from neutron.plugins.midonet.common import net_util - -LOG = logging.getLogger(__name__) - - -def handle_api_error(fn): - """Wrapper for methods that throws custom exceptions.""" - def wrapped(*args, **kwargs): - try: - return fn(*args, **kwargs) - except (w_exc.HTTPException, - exc.MidoApiConnectionError) as ex: - raise MidonetApiException(msg=ex) - return wrapped - - -class MidonetResourceNotFound(n_exc.NotFound): - message = _('MidoNet %(resource_type)s %(id)s could not be found') - - -class MidonetApiException(n_exc.NeutronException): - message = _("MidoNet API error: %(msg)s") - - -class MidoClient: - - def __init__(self, mido_api): - self.mido_api = mido_api - - @classmethod - def _fill_dto(cls, dto, fields): - for field_name, field_value in fields.iteritems(): - # We assume the setters are named the - # same way as the attributes themselves. - try: - getattr(dto, field_name)(field_value) - except AttributeError: - pass - return dto - - @classmethod - def _create_dto(cls, dto, fields): - return cls._fill_dto(dto, fields).create() - - @classmethod - def _update_dto(cls, dto, fields): - return cls._fill_dto(dto, fields).update() - - @handle_api_error - def create_bridge(self, **kwargs): - """Create a new bridge - - :param \**kwargs: configuration of the new bridge - :returns: newly created bridge - """ - LOG.debug(_("MidoClient.create_bridge called: " - "kwargs=%(kwargs)s"), {'kwargs': kwargs}) - return self._create_dto(self.mido_api.add_bridge(), kwargs) - - @handle_api_error - def delete_bridge(self, id): - """Delete a bridge - - :param id: id of the bridge - """ - LOG.debug(_("MidoClient.delete_bridge called: id=%(id)s"), {'id': id}) - return self.mido_api.delete_bridge(id) - - @handle_api_error - def get_bridge(self, id): - """Get a bridge - - :param id: id of the bridge - :returns: requested bridge. None if bridge does not exist. - """ - LOG.debug(_("MidoClient.get_bridge called: id=%s"), id) - try: - return self.mido_api.get_bridge(id) - except w_exc.HTTPNotFound: - raise MidonetResourceNotFound(resource_type='Bridge', id=id) - - @handle_api_error - def update_bridge(self, id, **kwargs): - """Update a bridge of the given id with the new fields - - :param id: id of the bridge - :param \**kwargs: the fields to update and their values - :returns: bridge object - """ - LOG.debug(_("MidoClient.update_bridge called: " - "id=%(id)s, kwargs=%(kwargs)s"), - {'id': id, 'kwargs': kwargs}) - try: - return self._update_dto(self.mido_api.get_bridge(id), kwargs) - except w_exc.HTTPNotFound: - raise MidonetResourceNotFound(resource_type='Bridge', id=id) - - @handle_api_error - def create_dhcp(self, bridge, gateway_ip, cidr, host_rts=None, - dns_servers=None): - """Create a new DHCP entry - - :param bridge: bridge object to add dhcp to - :param gateway_ip: IP address of gateway - :param cidr: subnet represented as x.x.x.x/y - :param host_rts: list of routes set in the host - :param dns_servers: list of dns servers - :returns: newly created dhcp - """ - LOG.debug(_("MidoClient.create_dhcp called: bridge=%(bridge)s, " - "cidr=%(cidr)s, gateway_ip=%(gateway_ip)s, " - "host_rts=%(host_rts)s, dns_servers=%(dns_servers)s"), - {'bridge': bridge, 'cidr': cidr, 'gateway_ip': gateway_ip, - 'host_rts': host_rts, 'dns_servers': dns_servers}) - self.mido_api.add_bridge_dhcp(bridge, gateway_ip, cidr, - host_rts=host_rts, - dns_nservers=dns_servers) - - @handle_api_error - def add_dhcp_host(self, bridge, cidr, ip, mac): - """Add DHCP host entry - - :param bridge: bridge the DHCP is configured for - :param cidr: subnet represented as x.x.x.x/y - :param ip: IP address - :param mac: MAC address - """ - LOG.debug(_("MidoClient.add_dhcp_host called: bridge=%(bridge)s, " - "cidr=%(cidr)s, ip=%(ip)s, mac=%(mac)s"), - {'bridge': bridge, 'cidr': cidr, 'ip': ip, 'mac': mac}) - subnet = bridge.get_dhcp_subnet(net_util.subnet_str(cidr)) - if subnet is None: - raise MidonetApiException(msg=_("Tried to add to" - "non-existent DHCP")) - - subnet.add_dhcp_host().ip_addr(ip).mac_addr(mac).create() - - @handle_api_error - def remove_dhcp_host(self, bridge, cidr, ip, mac): - """Remove DHCP host entry - - :param bridge: bridge the DHCP is configured for - :param cidr: subnet represented as x.x.x.x/y - :param ip: IP address - :param mac: MAC address - """ - LOG.debug(_("MidoClient.remove_dhcp_host called: bridge=%(bridge)s, " - "cidr=%(cidr)s, ip=%(ip)s, mac=%(mac)s"), - {'bridge': bridge, 'cidr': cidr, 'ip': ip, 'mac': mac}) - subnet = bridge.get_dhcp_subnet(net_util.subnet_str(cidr)) - if subnet is None: - LOG.warn(_("Tried to delete mapping from non-existent subnet")) - return - - for dh in subnet.get_dhcp_hosts(): - if dh.get_mac_addr() == mac and dh.get_ip_addr() == ip: - LOG.debug(_("MidoClient.remove_dhcp_host: Deleting %(dh)r"), - {"dh": dh}) - dh.delete() - - @handle_api_error - def delete_dhcp_host(self, bridge_id, cidr, ip, mac): - """Delete DHCP host entry - - :param bridge_id: id of the bridge of the DHCP - :param cidr: subnet represented as x.x.x.x/y - :param ip: IP address - :param mac: MAC address - """ - LOG.debug(_("MidoClient.delete_dhcp_host called: " - "bridge_id=%(bridge_id)s, cidr=%(cidr)s, ip=%(ip)s, " - "mac=%(mac)s"), {'bridge_id': bridge_id, - 'cidr': cidr, - 'ip': ip, 'mac': mac}) - bridge = self.get_bridge(bridge_id) - self.remove_dhcp_host(bridge, net_util.subnet_str(cidr), ip, mac) - - @handle_api_error - def delete_dhcp(self, bridge, cidr): - """Delete a DHCP entry - - :param bridge: bridge to remove DHCP from - :param cidr: subnet represented as x.x.x.x/y - """ - LOG.debug(_("MidoClient.delete_dhcp called: bridge=%(bridge)s, " - "cidr=%(cidr)s"), - {'bridge': bridge, 'cidr': cidr}) - dhcp_subnets = bridge.get_dhcp_subnets() - net_addr, net_len = net_util.net_addr(cidr) - if not dhcp_subnets: - raise MidonetApiException( - msg=_("Tried to delete non-existent DHCP")) - for dhcp in dhcp_subnets: - if dhcp.get_subnet_prefix() == net_addr: - dhcp.delete() - break - - @handle_api_error - def delete_port(self, id, delete_chains=False): - """Delete a port - - :param id: id of the port - """ - LOG.debug(_("MidoClient.delete_port called: id=%(id)s, " - "delete_chains=%(delete_chains)s"), - {'id': id, 'delete_chains': delete_chains}) - if delete_chains: - self.delete_port_chains(id) - - self.mido_api.delete_port(id) - - @handle_api_error - def get_port(self, id): - """Get a port - - :param id: id of the port - :returns: requested port. None if it does not exist - """ - LOG.debug(_("MidoClient.get_port called: id=%(id)s"), {'id': id}) - try: - return self.mido_api.get_port(id) - except w_exc.HTTPNotFound: - raise MidonetResourceNotFound(resource_type='Port', id=id) - - @handle_api_error - def add_bridge_port(self, bridge, **kwargs): - """Add a port on a bridge - - :param bridge: bridge to add a new port to - :param \**kwargs: configuration of the new port - :returns: newly created port - """ - LOG.debug(_("MidoClient.add_bridge_port called: " - "bridge=%(bridge)s, kwargs=%(kwargs)s"), - {'bridge': bridge, 'kwargs': kwargs}) - return self._create_dto(self.mido_api.add_bridge_port(bridge), kwargs) - - @handle_api_error - def update_port(self, id, **kwargs): - """Update a port of the given id with the new fields - - :param id: id of the port - :param \**kwargs: the fields to update and their values - """ - LOG.debug(_("MidoClient.update_port called: " - "id=%(id)s, kwargs=%(kwargs)s"), - {'id': id, 'kwargs': kwargs}) - try: - return self._update_dto(self.mido_api.get_port(id), kwargs) - except w_exc.HTTPNotFound: - raise MidonetResourceNotFound(resource_type='Port', id=id) - - @handle_api_error - def add_router_port(self, router, **kwargs): - """Add a new port to an existing router. - - :param router: router to add a new port to - :param \**kwargs: configuration of the new port - :returns: newly created port - """ - return self._create_dto(self.mido_api.add_router_port(router), kwargs) - - @handle_api_error - def create_router(self, **kwargs): - """Create a new router - - :param \**kwargs: configuration of the new router - :returns: newly created router - """ - LOG.debug(_("MidoClient.create_router called: " - "kwargs=%(kwargs)s"), {'kwargs': kwargs}) - return self._create_dto(self.mido_api.add_router(), kwargs) - - @handle_api_error - def delete_router(self, id): - """Delete a router - - :param id: id of the router - """ - LOG.debug(_("MidoClient.delete_router called: id=%(id)s"), {'id': id}) - return self.mido_api.delete_router(id) - - @handle_api_error - def get_router(self, id): - """Get a router with the given id - - :param id: id of the router - :returns: requested router object. None if it does not exist. - """ - LOG.debug(_("MidoClient.get_router called: id=%(id)s"), {'id': id}) - try: - return self.mido_api.get_router(id) - except w_exc.HTTPNotFound: - raise MidonetResourceNotFound(resource_type='Router', id=id) - - @handle_api_error - def update_router(self, id, **kwargs): - """Update a router of the given id with the new name - - :param id: id of the router - :param \**kwargs: the fields to update and their values - :returns: router object - """ - LOG.debug(_("MidoClient.update_router called: " - "id=%(id)s, kwargs=%(kwargs)s"), - {'id': id, 'kwargs': kwargs}) - try: - return self._update_dto(self.mido_api.get_router(id), kwargs) - except w_exc.HTTPNotFound: - raise MidonetResourceNotFound(resource_type='Router', id=id) - - @handle_api_error - def delete_route(self, id): - return self.mido_api.delete_route(id) - - @handle_api_error - def add_dhcp_route_option(self, bridge, cidr, gw_ip, dst_ip): - """Add Option121 route to subnet - - :param bridge: Bridge to add the option route to - :param cidr: subnet represented as x.x.x.x/y - :param gw_ip: IP address of the next hop - :param dst_ip: IP address of the destination, in x.x.x.x/y format - """ - LOG.debug(_("MidoClient.add_dhcp_route_option called: " - "bridge=%(bridge)s, cidr=%(cidr)s, gw_ip=%(gw_ip)s" - "dst_ip=%(dst_ip)s"), - {"bridge": bridge, "cidr": cidr, "gw_ip": gw_ip, - "dst_ip": dst_ip}) - subnet = bridge.get_dhcp_subnet(net_util.subnet_str(cidr)) - if subnet is None: - raise MidonetApiException( - msg=_("Tried to access non-existent DHCP")) - prefix, length = dst_ip.split("/") - routes = [{'destinationPrefix': prefix, 'destinationLength': length, - 'gatewayAddr': gw_ip}] - cur_routes = subnet.get_opt121_routes() - if cur_routes: - routes = routes + cur_routes - subnet.opt121_routes(routes).update() - - @handle_api_error - def link(self, port, peer_id): - """Link a port to a given peerId.""" - self.mido_api.link(port, peer_id) - - @handle_api_error - def delete_port_routes(self, routes, port_id): - """Remove routes whose next hop port is the given port ID.""" - for route in routes: - if route.get_next_hop_port() == port_id: - self.mido_api.delete_route(route.get_id()) - - @handle_api_error - def get_router_routes(self, router_id): - """Get all routes for the given router.""" - return self.mido_api.get_router_routes(router_id) - - @handle_api_error - def unlink(self, port): - """Unlink a port - - :param port: port object - """ - LOG.debug(_("MidoClient.unlink called: port=%(port)s"), - {'port': port}) - if port.get_peer_id(): - self.mido_api.unlink(port) - else: - LOG.warn(_("Attempted to unlink a port that was not linked. %s"), - port.get_id()) - - @handle_api_error - def remove_rules_by_property(self, tenant_id, chain_name, key, value): - """Remove all the rules that match the provided key and value.""" - LOG.debug(_("MidoClient.remove_rules_by_property called: " - "tenant_id=%(tenant_id)s, chain_name=%(chain_name)s" - "key=%(key)s, value=%(value)s"), - {'tenant_id': tenant_id, 'chain_name': chain_name, - 'key': key, 'value': value}) - chain = self.get_chain_by_name(tenant_id, chain_name) - if chain is None: - raise MidonetResourceNotFound(resource_type='Chain', - id=chain_name) - - for r in chain.get_rules(): - if key in r.get_properties(): - if r.get_properties()[key] == value: - self.mido_api.delete_rule(r.get_id()) - - @handle_api_error - def add_router_chains(self, router, inbound_chain_name, - outbound_chain_name): - """Create chains for a new router. - - Creates inbound and outbound chains for the router with the given - names, and the new chains are set on the router. - - :param router: router to set chains for - :param inbound_chain_name: Name of the inbound chain - :param outbound_chain_name: Name of the outbound chain - """ - LOG.debug(_("MidoClient.create_router_chains called: " - "router=%(router)s, inbound_chain_name=%(in_chain)s, " - "outbound_chain_name=%(out_chain)s"), - {"router": router, "in_chain": inbound_chain_name, - "out_chain": outbound_chain_name}) - tenant_id = router.get_tenant_id() - - inbound_chain = self.mido_api.add_chain().tenant_id(tenant_id).name( - inbound_chain_name,).create() - outbound_chain = self.mido_api.add_chain().tenant_id(tenant_id).name( - outbound_chain_name).create() - - # set chains to in/out filters - router.inbound_filter_id(inbound_chain.get_id()).outbound_filter_id( - outbound_chain.get_id()).update() - return inbound_chain, outbound_chain - - @handle_api_error - def delete_router_chains(self, id): - """Deletes chains of a router. - - :param id: router ID to delete chains of - """ - LOG.debug(_("MidoClient.delete_router_chains called: " - "id=%(id)s"), {'id': id}) - router = self.get_router(id) - if (router.get_inbound_filter_id()): - self.mido_api.delete_chain(router.get_inbound_filter_id()) - - if (router.get_outbound_filter_id()): - self.mido_api.delete_chain(router.get_outbound_filter_id()) - - @handle_api_error - def delete_port_chains(self, id): - """Deletes chains of a port. - - :param id: port ID to delete chains of - """ - LOG.debug(_("MidoClient.delete_port_chains called: " - "id=%(id)s"), {'id': id}) - port = self.get_port(id) - if (port.get_inbound_filter_id()): - self.mido_api.delete_chain(port.get_inbound_filter_id()) - - if (port.get_outbound_filter_id()): - self.mido_api.delete_chain(port.get_outbound_filter_id()) - - @handle_api_error - def get_link_port(self, router, peer_router_id): - """Setup a route on the router to the next hop router.""" - LOG.debug(_("MidoClient.get_link_port called: " - "router=%(router)s, peer_router_id=%(peer_router_id)s"), - {'router': router, 'peer_router_id': peer_router_id}) - # Find the port linked between the two routers - link_port = None - for p in router.get_peer_ports(): - if p.get_device_id() == peer_router_id: - link_port = p - break - return link_port - - @handle_api_error - def add_router_route(self, router, type='Normal', - src_network_addr=None, src_network_length=None, - dst_network_addr=None, dst_network_length=None, - next_hop_port=None, next_hop_gateway=None, - weight=100): - """Setup a route on the router.""" - return self.mido_api.add_router_route( - router, type=type, src_network_addr=src_network_addr, - src_network_length=src_network_length, - dst_network_addr=dst_network_addr, - dst_network_length=dst_network_length, - next_hop_port=next_hop_port, next_hop_gateway=next_hop_gateway, - weight=weight) - - @handle_api_error - def add_static_nat(self, tenant_id, chain_name, from_ip, to_ip, port_id, - nat_type='dnat', **kwargs): - """Add a static NAT entry - - :param tenant_id: owner fo the chain to add a NAT to - :param chain_name: name of the chain to add a NAT to - :param from_ip: IP to translate from - :param from_ip: IP to translate from - :param to_ip: IP to translate to - :param port_id: port to match on - :param nat_type: 'dnat' or 'snat' - """ - LOG.debug(_("MidoClient.add_static_nat called: " - "tenant_id=%(tenant_id)s, chain_name=%(chain_name)s, " - "from_ip=%(from_ip)s, to_ip=%(to_ip)s, " - "port_id=%(port_id)s, nat_type=%(nat_type)s"), - {'tenant_id': tenant_id, 'chain_name': chain_name, - 'from_ip': from_ip, 'to_ip': to_ip, - 'portid': port_id, 'nat_type': nat_type}) - if nat_type not in ['dnat', 'snat']: - raise ValueError(_("Invalid NAT type passed in %s") % nat_type) - - chain = self.get_chain_by_name(tenant_id, chain_name) - nat_targets = [] - nat_targets.append( - {'addressFrom': to_ip, 'addressTo': to_ip, - 'portFrom': 0, 'portTo': 0}) - - rule = chain.add_rule().type(nat_type).flow_action('accept').position( - 1).nat_targets(nat_targets).properties(kwargs) - - if nat_type == 'dnat': - rule = rule.nw_dst_address(from_ip).nw_dst_length(32).in_ports( - [port_id]) - else: - rule = rule.nw_src_address(from_ip).nw_src_length(32).out_ports( - [port_id]) - - return rule.create() - - @handle_api_error - def add_dynamic_snat(self, tenant_id, pre_chain_name, post_chain_name, - snat_ip, port_id, **kwargs): - """Add SNAT masquerading rule - - MidoNet requires two rules on the router, one to do NAT to a range of - ports, and another to retrieve back the original IP in the return - flow. - """ - pre_chain = self.get_chain_by_name(tenant_id, pre_chain_name) - post_chain = self.get_chain_by_name(tenant_id, post_chain_name) - - pre_chain.add_rule().nw_dst_address(snat_ip).nw_dst_length( - 32).type('rev_snat').flow_action('accept').in_ports( - [port_id]).properties(kwargs).position(1).create() - - nat_targets = [] - nat_targets.append( - {'addressFrom': snat_ip, 'addressTo': snat_ip, - 'portFrom': 1, 'portTo': 65535}) - - post_chain.add_rule().type('snat').flow_action( - 'accept').nat_targets(nat_targets).out_ports( - [port_id]).properties(kwargs).position(1).create() - - @handle_api_error - def remove_static_route(self, router, ip): - """Remove static route for the IP - - :param router: next hop router to remove the routes to - :param ip: IP address of the route to remove - """ - LOG.debug(_("MidoClient.remote_static_route called: " - "router=%(router)s, ip=%(ip)s"), - {'router': router, 'ip': ip}) - for r in router.get_routes(): - if (r.get_dst_network_addr() == ip and - r.get_dst_network_length() == 32): - self.mido_api.delete_route(r.get_id()) - - @handle_api_error - def update_port_chains(self, port, inbound_chain_id, outbound_chain_id): - """Bind inbound and outbound chains to the port.""" - LOG.debug(_("MidoClient.update_port_chains called: port=%(port)s" - "inbound_chain_id=%(inbound_chain_id)s, " - "outbound_chain_id=%(outbound_chain_id)s"), - {"port": port, "inbound_chain_id": inbound_chain_id, - "outbound_chain_id": outbound_chain_id}) - port.inbound_filter_id(inbound_chain_id).outbound_filter_id( - outbound_chain_id).update() - - @handle_api_error - def create_chain(self, tenant_id, name): - """Create a new chain.""" - LOG.debug(_("MidoClient.create_chain called: tenant_id=%(tenant_id)s " - " name=%(name)s"), {"tenant_id": tenant_id, "name": name}) - return self.mido_api.add_chain().tenant_id(tenant_id).name( - name).create() - - @handle_api_error - def delete_chain(self, id): - """Delete chain matching the ID.""" - LOG.debug(_("MidoClient.delete_chain called: id=%(id)s"), {"id": id}) - self.mido_api.delete_chain(id) - - @handle_api_error - def delete_chains_by_names(self, tenant_id, names): - """Delete chains matching the names given for a tenant.""" - LOG.debug(_("MidoClient.delete_chains_by_names called: " - "tenant_id=%(tenant_id)s names=%(names)s "), - {"tenant_id": tenant_id, "names": names}) - chains = self.mido_api.get_chains({'tenant_id': tenant_id}) - for c in chains: - if c.get_name() in names: - self.mido_api.delete_chain(c.get_id()) - - @handle_api_error - def get_chain_by_name(self, tenant_id, name): - """Get the chain by its name.""" - LOG.debug(_("MidoClient.get_chain_by_name called: " - "tenant_id=%(tenant_id)s name=%(name)s "), - {"tenant_id": tenant_id, "name": name}) - for c in self.mido_api.get_chains({'tenant_id': tenant_id}): - if c.get_name() == name: - return c - return None - - @handle_api_error - def get_port_group_by_name(self, tenant_id, name): - """Get the port group by name.""" - LOG.debug(_("MidoClient.get_port_group_by_name called: " - "tenant_id=%(tenant_id)s name=%(name)s "), - {"tenant_id": tenant_id, "name": name}) - for p in self.mido_api.get_port_groups({'tenant_id': tenant_id}): - if p.get_name() == name: - return p - return None - - @handle_api_error - def create_port_group(self, tenant_id, name): - """Create a port group - - Create a new port group for a given name and ID. - """ - LOG.debug(_("MidoClient.create_port_group called: " - "tenant_id=%(tenant_id)s name=%(name)s"), - {"tenant_id": tenant_id, "name": name}) - return self.mido_api.add_port_group().tenant_id(tenant_id).name( - name).create() - - @handle_api_error - def delete_port_group_by_name(self, tenant_id, name): - """Delete port group matching the name given for a tenant.""" - LOG.debug(_("MidoClient.delete_port_group_by_name called: " - "tenant_id=%(tenant_id)s name=%(name)s "), - {"tenant_id": tenant_id, "name": name}) - pgs = self.mido_api.get_port_groups({'tenant_id': tenant_id}) - for pg in pgs: - if pg.get_name() == name: - LOG.debug(_("Deleting pg %(id)s"), {"id": pg.get_id()}) - self.mido_api.delete_port_group(pg.get_id()) - - @handle_api_error - def add_port_to_port_group_by_name(self, tenant_id, name, port_id): - """Add a port to a port group with the given name.""" - LOG.debug(_("MidoClient.add_port_to_port_group_by_name called: " - "tenant_id=%(tenant_id)s name=%(name)s " - "port_id=%(port_id)s"), - {"tenant_id": tenant_id, "name": name, "port_id": port_id}) - pg = self.get_port_group_by_name(tenant_id, name) - if pg is None: - raise MidonetResourceNotFound(resource_type='PortGroup', id=name) - - pg = pg.add_port_group_port().port_id(port_id).create() - return pg - - @handle_api_error - def remove_port_from_port_groups(self, port_id): - """Remove a port binding from all the port groups.""" - LOG.debug(_("MidoClient.remove_port_from_port_groups called: " - "port_id=%(port_id)s"), {"port_id": port_id}) - port = self.get_port(port_id) - for pg in port.get_port_groups(): - pg.delete() - - @handle_api_error - def add_chain_rule(self, chain, action='accept', **kwargs): - """Create a new accept chain rule.""" - self.mido_api.add_chain_rule(chain, action, **kwargs) diff --git a/neutron/plugins/midonet/plugin.py b/neutron/plugins/midonet/plugin.py deleted file mode 100644 index 9a706d4a5..000000000 --- a/neutron/plugins/midonet/plugin.py +++ /dev/null @@ -1,1258 +0,0 @@ -# vim: tabstop=4 shiftwidth=4 softtabstop=4 - -# Copyright (C) 2012 Midokura Japan K.K. -# Copyright (C) 2013 Midokura PTE LTD -# 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: Takaaki Suzuki, Midokura Japan KK -# @author: Tomoe Sugihara, Midokura Japan KK -# @author: Ryu Ishimoto, Midokura Japan KK -# @author: Rossella Sblendido, Midokura Japan KK -# @author: Duarte Nunes, Midokura Japan KK - -from midonetclient import api -from oslo.config import cfg -from sqlalchemy.orm import exc as sa_exc - -from neutron.api.v2 import attributes -from neutron.common import constants -from neutron.common import exceptions as n_exc -from neutron.common import rpc_compat -from neutron.common import topics -from neutron.db import agents_db -from neutron.db import agentschedulers_db -from neutron.db import db_base_plugin_v2 -from neutron.db import dhcp_rpc_base -from neutron.db import external_net_db -from neutron.db import l3_db -from neutron.db import models_v2 -from neutron.db import portbindings_db -from neutron.db import securitygroups_db -from neutron.extensions import external_net as ext_net -from neutron.extensions import l3 -from neutron.extensions import portbindings -from neutron.extensions import securitygroup as ext_sg -from neutron.openstack.common import excutils -from neutron.openstack.common import log as logging -from neutron.plugins.midonet.common import config # noqa -from neutron.plugins.midonet.common import net_util -from neutron.plugins.midonet import midonet_lib - -LOG = logging.getLogger(__name__) - -EXTERNAL_GW_INFO = l3.EXTERNAL_GW_INFO - -METADATA_DEFAULT_IP = "169.254.169.254/32" -OS_FLOATING_IP_RULE_KEY = 'OS_FLOATING_IP' -OS_SG_RULE_KEY = 'OS_SG_RULE_ID' -OS_TENANT_ROUTER_RULE_KEY = 'OS_TENANT_ROUTER_RULE' -PRE_ROUTING_CHAIN_NAME = "OS_PRE_ROUTING_%s" -PORT_INBOUND_CHAIN_NAME = "OS_PORT_%s_INBOUND" -PORT_OUTBOUND_CHAIN_NAME = "OS_PORT_%s_OUTBOUND" -POST_ROUTING_CHAIN_NAME = "OS_POST_ROUTING_%s" -SG_INGRESS_CHAIN_NAME = "OS_SG_%s_INGRESS" -SG_EGRESS_CHAIN_NAME = "OS_SG_%s_EGRESS" -SG_PORT_GROUP_NAME = "OS_PG_%s" -SNAT_RULE = 'SNAT' - - -def _get_nat_ips(type, fip): - """Get NAT IP address information. - - From the route type given, determine the source and target IP addresses - from the provided floating IP DB object. - """ - if type == 'pre-routing': - return fip["floating_ip_address"], fip["fixed_ip_address"] - elif type == 'post-routing': - return fip["fixed_ip_address"], fip["floating_ip_address"] - else: - raise ValueError(_("Invalid nat_type %s") % type) - - -def _nat_chain_names(router_id): - """Get the chain names for NAT. - - These names are used to associate MidoNet chains to the NAT rules - applied to the router. For each of these, there are two NAT types, - 'dnat' and 'snat' that are returned as keys, and the corresponding - chain names as their values. - """ - pre_routing_name = PRE_ROUTING_CHAIN_NAME % router_id - post_routing_name = POST_ROUTING_CHAIN_NAME % router_id - return {'pre-routing': pre_routing_name, 'post-routing': post_routing_name} - - -def _sg_chain_names(sg_id): - """Get the chain names for security group. - - These names are used to associate a security group to MidoNet chains. - There are two names for ingress and egress security group directions. - """ - ingress = SG_INGRESS_CHAIN_NAME % sg_id - egress = SG_EGRESS_CHAIN_NAME % sg_id - return {'ingress': ingress, 'egress': egress} - - -def _port_chain_names(port_id): - """Get the chain names for a port. - - These are chains to hold security group chains. - """ - inbound = PORT_INBOUND_CHAIN_NAME % port_id - outbound = PORT_OUTBOUND_CHAIN_NAME % port_id - return {'inbound': inbound, 'outbound': outbound} - - -def _sg_port_group_name(sg_id): - """Get the port group name for security group.. - - This name is used to associate a security group to MidoNet port groups. - """ - return SG_PORT_GROUP_NAME % sg_id - - -def _rule_direction(sg_direction): - """Convert the SG direction to MidoNet direction - - MidoNet terms them 'inbound' and 'outbound' instead of 'ingress' and - 'egress'. Also, the direction is reversed since MidoNet sees it - from the network port's point of view, not the VM's. - """ - if sg_direction == 'ingress': - return 'outbound' - elif sg_direction == 'egress': - return 'inbound' - else: - raise ValueError(_("Unrecognized direction %s") % sg_direction) - - -def _is_router_interface_port(port): - """Check whether the given port is a router interface port.""" - device_owner = port['device_owner'] - return (device_owner in l3_db.DEVICE_OWNER_ROUTER_INTF) - - -def _is_router_gw_port(port): - """Check whether the given port is a router gateway port.""" - device_owner = port['device_owner'] - return (device_owner in l3_db.DEVICE_OWNER_ROUTER_GW) - - -def _is_vif_port(port): - """Check whether the given port is a standard VIF port.""" - device_owner = port['device_owner'] - return (not _is_dhcp_port(port) and - device_owner not in (l3_db.DEVICE_OWNER_ROUTER_GW, - l3_db.DEVICE_OWNER_ROUTER_INTF)) - - -def _is_dhcp_port(port): - """Check whether the given port is a DHCP port.""" - device_owner = port['device_owner'] - return device_owner.startswith(constants.DEVICE_OWNER_DHCP) - - -def _check_resource_exists(func, id, name, raise_exc=False): - """Check whether the given resource exists in MidoNet data store.""" - try: - func(id) - except midonet_lib.MidonetResourceNotFound as exc: - LOG.error(_("There is no %(name)s with ID %(id)s in MidoNet."), - {"name": name, "id": id}) - if raise_exc: - raise MidonetPluginException(msg=exc) - - -class MidoRpcCallbacks(rpc_compat.RpcCallback, - dhcp_rpc_base.DhcpRpcCallbackMixin): - RPC_API_VERSION = '1.1' - - -class MidonetPluginException(n_exc.NeutronException): - message = _("%(msg)s") - - -class MidonetPluginV2(db_base_plugin_v2.NeutronDbPluginV2, - portbindings_db.PortBindingMixin, - external_net_db.External_net_db_mixin, - l3_db.L3_NAT_db_mixin, - agentschedulers_db.DhcpAgentSchedulerDbMixin, - securitygroups_db.SecurityGroupDbMixin): - - supported_extension_aliases = ['external-net', 'router', 'security-group', - 'agent', 'dhcp_agent_scheduler', 'binding'] - __native_bulk_support = False - - def __init__(self): - super(MidonetPluginV2, self).__init__() - # Read config values - midonet_conf = cfg.CONF.MIDONET - midonet_uri = midonet_conf.midonet_uri - admin_user = midonet_conf.username - admin_pass = midonet_conf.password - admin_project_id = midonet_conf.project_id - self.provider_router_id = midonet_conf.provider_router_id - self.provider_router = None - - self.mido_api = api.MidonetApi(midonet_uri, admin_user, - admin_pass, - project_id=admin_project_id) - self.client = midonet_lib.MidoClient(self.mido_api) - - # self.provider_router_id should have been set. - if self.provider_router_id is None: - msg = _('provider_router_id should be configured in the plugin ' - 'config file') - LOG.exception(msg) - raise MidonetPluginException(msg=msg) - - self.setup_rpc() - - self.base_binding_dict = { - portbindings.VIF_TYPE: portbindings.VIF_TYPE_MIDONET, - portbindings.VIF_DETAILS: { - # TODO(rkukura): Replace with new VIF security details - portbindings.CAP_PORT_FILTER: - 'security-group' in self.supported_extension_aliases}} - - def _get_provider_router(self): - if self.provider_router is None: - self.provider_router = self.client.get_router( - self.provider_router_id) - return self.provider_router - - def _dhcp_mappings(self, context, fixed_ips, mac): - for fixed_ip in fixed_ips: - subnet = self._get_subnet(context, fixed_ip["subnet_id"]) - if subnet["ip_version"] == 6: - # TODO(ryu) handle IPv6 - continue - if not subnet["enable_dhcp"]: - # Skip if DHCP is disabled - continue - yield subnet['cidr'], fixed_ip["ip_address"], mac - - def _metadata_subnets(self, context, fixed_ips): - for fixed_ip in fixed_ips: - subnet = self._get_subnet(context, fixed_ip["subnet_id"]) - if subnet["ip_version"] == 6: - continue - yield subnet['cidr'], fixed_ip["ip_address"] - - def _initialize_port_chains(self, port, in_chain, out_chain, sg_ids): - - tenant_id = port["tenant_id"] - - position = 1 - # mac spoofing protection - self._add_chain_rule(in_chain, action='drop', - dl_src=port["mac_address"], inv_dl_src=True, - position=position) - - # ip spoofing protection - for fixed_ip in port["fixed_ips"]: - position += 1 - self._add_chain_rule(in_chain, action="drop", - src_addr=fixed_ip["ip_address"] + "/32", - inv_nw_src=True, dl_type=0x0800, # IPv4 - position=position) - - # conntrack - position += 1 - self._add_chain_rule(in_chain, action='accept', - match_forward_flow=True, - position=position) - - # Reset the position to process egress - position = 1 - - # Add rule for SGs - if sg_ids: - for sg_id in sg_ids: - chain_name = _sg_chain_names(sg_id)["ingress"] - chain = self.client.get_chain_by_name(tenant_id, chain_name) - self._add_chain_rule(out_chain, action='jump', - jump_chain_id=chain.get_id(), - jump_chain_name=chain_name, - position=position) - position += 1 - - # add reverse flow matching at the end - self._add_chain_rule(out_chain, action='accept', - match_return_flow=True, - position=position) - position += 1 - - # fall back DROP rule at the end except for ARP - self._add_chain_rule(out_chain, action='drop', - dl_type=0x0806, # ARP - inv_dl_type=True, position=position) - - def _bind_port_to_sgs(self, context, port, sg_ids): - self._process_port_create_security_group(context, port, sg_ids) - if sg_ids is not None: - for sg_id in sg_ids: - pg_name = _sg_port_group_name(sg_id) - self.client.add_port_to_port_group_by_name( - port["tenant_id"], pg_name, port["id"]) - - def _unbind_port_from_sgs(self, context, port_id): - self._delete_port_security_group_bindings(context, port_id) - self.client.remove_port_from_port_groups(port_id) - - def _create_accept_chain_rule(self, context, sg_rule, chain=None): - direction = sg_rule["direction"] - tenant_id = sg_rule["tenant_id"] - sg_id = sg_rule["security_group_id"] - chain_name = _sg_chain_names(sg_id)[direction] - - if chain is None: - chain = self.client.get_chain_by_name(tenant_id, chain_name) - - pg_id = None - if sg_rule["remote_group_id"] is not None: - pg_name = _sg_port_group_name(sg_id) - pg = self.client.get_port_group_by_name(tenant_id, pg_name) - pg_id = pg.get_id() - - props = {OS_SG_RULE_KEY: str(sg_rule["id"])} - - # Determine source or destination address by looking at direction - src_pg_id = dst_pg_id = None - src_addr = dst_addr = None - src_port_to = dst_port_to = None - src_port_from = dst_port_from = None - if direction == "egress": - dst_pg_id = pg_id - dst_addr = sg_rule["remote_ip_prefix"] - dst_port_from = sg_rule["port_range_min"] - dst_port_to = sg_rule["port_range_max"] - else: - src_pg_id = pg_id - src_addr = sg_rule["remote_ip_prefix"] - src_port_from = sg_rule["port_range_min"] - src_port_to = sg_rule["port_range_max"] - - return self._add_chain_rule( - chain, action='accept', port_group_src=src_pg_id, - port_group_dst=dst_pg_id, - src_addr=src_addr, src_port_from=src_port_from, - src_port_to=src_port_to, - dst_addr=dst_addr, dst_port_from=dst_port_from, - dst_port_to=dst_port_to, - nw_proto=net_util.get_protocol_value(sg_rule["protocol"]), - dl_type=net_util.get_ethertype_value(sg_rule["ethertype"]), - properties=props) - - def _remove_nat_rules(self, context, fip): - router = self.client.get_router(fip["router_id"]) - self.client.remove_static_route(self._get_provider_router(), - fip["floating_ip_address"]) - - chain_names = _nat_chain_names(router.get_id()) - for _type, name in chain_names.iteritems(): - self.client.remove_rules_by_property( - router.get_tenant_id(), name, - OS_FLOATING_IP_RULE_KEY, fip["id"]) - - def setup_rpc(self): - # RPC support - self.topic = topics.PLUGIN - self.conn = rpc_compat.create_connection(new=True) - self.endpoints = [MidoRpcCallbacks(), - agents_db.AgentExtRpcCallback()] - self.conn.create_consumer(self.topic, self.endpoints, - fanout=False) - # Consume from all consumers in threads - self.conn.consume_in_threads() - - def create_subnet(self, context, subnet): - """Create Neutron subnet. - - Creates a Neutron subnet and a DHCP entry in MidoNet bridge. - """ - LOG.debug(_("MidonetPluginV2.create_subnet called: subnet=%r"), subnet) - - s = subnet["subnet"] - net = super(MidonetPluginV2, self).get_network( - context, subnet['subnet']['network_id'], fields=None) - - session = context.session - with session.begin(subtransactions=True): - sn_entry = super(MidonetPluginV2, self).create_subnet(context, - subnet) - bridge = self.client.get_bridge(sn_entry['network_id']) - - gateway_ip = s['gateway_ip'] - cidr = s['cidr'] - if s['enable_dhcp']: - dns_nameservers = None - host_routes = None - if s['dns_nameservers'] is not attributes.ATTR_NOT_SPECIFIED: - dns_nameservers = s['dns_nameservers'] - - if s['host_routes'] is not attributes.ATTR_NOT_SPECIFIED: - host_routes = s['host_routes'] - - self.client.create_dhcp(bridge, gateway_ip, cidr, - host_rts=host_routes, - dns_servers=dns_nameservers) - - # For external network, link the bridge to the provider router. - if net['router:external']: - self._link_bridge_to_gw_router( - bridge, self._get_provider_router(), gateway_ip, cidr) - - LOG.debug(_("MidonetPluginV2.create_subnet exiting: sn_entry=%r"), - sn_entry) - return sn_entry - - def delete_subnet(self, context, id): - """Delete Neutron subnet. - - Delete neutron network and its corresponding MidoNet bridge. - """ - LOG.debug(_("MidonetPluginV2.delete_subnet called: id=%s"), id) - subnet = super(MidonetPluginV2, self).get_subnet(context, id, - fields=None) - net = super(MidonetPluginV2, self).get_network(context, - subnet['network_id'], - fields=None) - session = context.session - with session.begin(subtransactions=True): - - super(MidonetPluginV2, self).delete_subnet(context, id) - bridge = self.client.get_bridge(subnet['network_id']) - if subnet['enable_dhcp']: - self.client.delete_dhcp(bridge, subnet['cidr']) - - # If the network is external, clean up routes, links, ports - if net[ext_net.EXTERNAL]: - self._unlink_bridge_from_gw_router( - bridge, self._get_provider_router()) - - LOG.debug(_("MidonetPluginV2.delete_subnet exiting")) - - def create_network(self, context, network): - """Create Neutron network. - - Create a new Neutron network and its corresponding MidoNet bridge. - """ - LOG.debug(_('MidonetPluginV2.create_network called: network=%r'), - network) - net_data = network['network'] - tenant_id = self._get_tenant_id_for_create(context, net_data) - net_data['tenant_id'] = tenant_id - self._ensure_default_security_group(context, tenant_id) - - bridge = self.client.create_bridge(**net_data) - net_data['id'] = bridge.get_id() - - session = context.session - with session.begin(subtransactions=True): - net = super(MidonetPluginV2, self).create_network(context, network) - self._process_l3_create(context, net, net_data) - - LOG.debug(_("MidonetPluginV2.create_network exiting: net=%r"), net) - return net - - def update_network(self, context, id, network): - """Update Neutron network. - - Update an existing Neutron network and its corresponding MidoNet - bridge. - """ - LOG.debug(_("MidonetPluginV2.update_network called: id=%(id)r, " - "network=%(network)r"), {'id': id, 'network': network}) - session = context.session - with session.begin(subtransactions=True): - net = super(MidonetPluginV2, self).update_network( - context, id, network) - self._process_l3_update(context, net, network['network']) - self.client.update_bridge(id, **network['network']) - - LOG.debug(_("MidonetPluginV2.update_network exiting: net=%r"), net) - return net - - def get_network(self, context, id, fields=None): - """Get Neutron network. - - Retrieves a Neutron network and its corresponding MidoNet bridge. - """ - LOG.debug(_("MidonetPluginV2.get_network called: id=%(id)r, " - "fields=%(fields)r"), {'id': id, 'fields': fields}) - qnet = super(MidonetPluginV2, self).get_network(context, id, fields) - self.client.get_bridge(id) - - LOG.debug(_("MidonetPluginV2.get_network exiting: qnet=%r"), qnet) - return qnet - - def delete_network(self, context, id): - """Delete a network and its corresponding MidoNet bridge.""" - LOG.debug(_("MidonetPluginV2.delete_network called: id=%r"), id) - self.client.delete_bridge(id) - try: - with context.session.begin(subtransactions=True): - self._process_l3_delete(context, id) - super(MidonetPluginV2, self).delete_network(context, id) - except Exception: - with excutils.save_and_reraise_exception(): - LOG.error(_('Failed to delete neutron db, while Midonet ' - 'bridge=%r had been deleted'), id) - - def create_port(self, context, port): - """Create a L2 port in Neutron/MidoNet.""" - LOG.debug(_("MidonetPluginV2.create_port called: port=%r"), port) - port_data = port['port'] - - # Create a bridge port in MidoNet and set the bridge port ID as the - # port ID in Neutron. - bridge = self.client.get_bridge(port_data["network_id"]) - tenant_id = bridge.get_tenant_id() - asu = port_data.get("admin_state_up", True) - bridge_port = self.client.add_bridge_port(bridge, - admin_state_up=asu) - port_data["id"] = bridge_port.get_id() - - try: - session = context.session - with session.begin(subtransactions=True): - # Create a Neutron port - new_port = super(MidonetPluginV2, self).create_port(context, - port) - port_data.update(new_port) - self._ensure_default_security_group_on_port(context, - port) - if _is_vif_port(port_data): - # Bind security groups to the port - sg_ids = self._get_security_groups_on_port(context, port) - self._bind_port_to_sgs(context, new_port, sg_ids) - - # Create port chains - port_chains = {} - for d, name in _port_chain_names( - new_port["id"]).iteritems(): - port_chains[d] = self.client.create_chain(tenant_id, - name) - - self._initialize_port_chains(port_data, - port_chains['inbound'], - port_chains['outbound'], - sg_ids) - - # Update the port with the chain - self.client.update_port_chains( - bridge_port, port_chains["inbound"].get_id(), - port_chains["outbound"].get_id()) - - # DHCP mapping is only for VIF ports - for cidr, ip, mac in self._dhcp_mappings( - context, port_data["fixed_ips"], - port_data["mac_address"]): - self.client.add_dhcp_host(bridge, cidr, ip, mac) - - elif _is_dhcp_port(port_data): - # For DHCP port, add a metadata route - for cidr, ip in self._metadata_subnets( - context, port_data["fixed_ips"]): - self.client.add_dhcp_route_option(bridge, cidr, ip, - METADATA_DEFAULT_IP) - - self._process_portbindings_create_and_update(context, - port_data, new_port) - except Exception as ex: - # Try removing the MidoNet port before raising an exception. - with excutils.save_and_reraise_exception(): - LOG.error(_("Failed to create a port on network %(net_id)s: " - "%(err)s"), - {"net_id": port_data["network_id"], "err": ex}) - self.client.delete_port(bridge_port.get_id()) - - LOG.debug(_("MidonetPluginV2.create_port exiting: port=%r"), new_port) - return new_port - - def get_port(self, context, id, fields=None): - """Retrieve port.""" - LOG.debug(_("MidonetPluginV2.get_port called: id=%(id)s " - "fields=%(fields)r"), {'id': id, 'fields': fields}) - port = super(MidonetPluginV2, self).get_port(context, id, fields) - "Check if the port exists in MidoNet DB""" - try: - self.client.get_port(id) - except midonet_lib.MidonetResourceNotFound as exc: - LOG.error(_("There is no port with ID %(id)s in MidoNet."), - {"id": id}) - port['status'] = constants.PORT_STATUS_ERROR - raise exc - LOG.debug(_("MidonetPluginV2.get_port exiting: port=%r"), port) - return port - - def get_ports(self, context, filters=None, fields=None): - """List neutron ports and verify that they exist in MidoNet.""" - LOG.debug(_("MidonetPluginV2.get_ports called: filters=%(filters)s " - "fields=%(fields)r"), - {'filters': filters, 'fields': fields}) - ports = super(MidonetPluginV2, self).get_ports(context, filters, - fields) - return ports - - def delete_port(self, context, id, l3_port_check=True): - """Delete a neutron port and corresponding MidoNet bridge port.""" - LOG.debug(_("MidonetPluginV2.delete_port called: id=%(id)s " - "l3_port_check=%(l3_port_check)r"), - {'id': id, 'l3_port_check': l3_port_check}) - # if needed, check to see if this is a port owned by - # and l3-router. If so, we should prevent deletion. - if l3_port_check: - self.prevent_l3_port_deletion(context, id) - - self.disassociate_floatingips(context, id) - port = self.get_port(context, id) - device_id = port['device_id'] - # If this port is for router interface/gw, unlink and delete. - if _is_router_interface_port(port): - self._unlink_bridge_from_router(device_id, id) - elif _is_router_gw_port(port): - # Gateway removed - # Remove all the SNAT rules that are tagged. - router = self._get_router(context, device_id) - tenant_id = router["tenant_id"] - chain_names = _nat_chain_names(device_id) - for _type, name in chain_names.iteritems(): - self.client.remove_rules_by_property( - tenant_id, name, OS_TENANT_ROUTER_RULE_KEY, - SNAT_RULE) - # Remove the default routes and unlink - self._remove_router_gateway(port['device_id']) - - self.client.delete_port(id, delete_chains=True) - try: - for cidr, ip, mac in self._dhcp_mappings( - context, port["fixed_ips"], port["mac_address"]): - self.client.delete_dhcp_host(port["network_id"], cidr, ip, - mac) - except Exception: - LOG.error(_("Failed to delete DHCP mapping for port %(id)s"), - {"id": id}) - - super(MidonetPluginV2, self).delete_port(context, id) - - def update_port(self, context, id, port): - """Handle port update, including security groups and fixed IPs.""" - with context.session.begin(subtransactions=True): - - # Get the port and save the fixed IPs - old_port = self._get_port(context, id) - net_id = old_port["network_id"] - mac = old_port["mac_address"] - old_ips = old_port["fixed_ips"] - # update the port DB - p = super(MidonetPluginV2, self).update_port(context, id, port) - - if "admin_state_up" in port["port"]: - asu = port["port"]["admin_state_up"] - mido_port = self.client.update_port(id, admin_state_up=asu) - - # If we're changing the admin_state_up flag and the port is - # associated with a router, then we also need to update the - # peer port. - if _is_router_interface_port(p): - self.client.update_port(mido_port.get_peer_id(), - admin_state_up=asu) - - new_ips = p["fixed_ips"] - if new_ips: - bridge = self.client.get_bridge(net_id) - # If it's a DHCP port, add a route to reach the MD server - if _is_dhcp_port(p): - for cidr, ip in self._metadata_subnets( - context, new_ips): - self.client.add_dhcp_route_option( - bridge, cidr, ip, METADATA_DEFAULT_IP) - else: - # IPs have changed. Re-map the DHCP entries - for cidr, ip, mac in self._dhcp_mappings( - context, old_ips, mac): - self.client.remove_dhcp_host( - bridge, cidr, ip, mac) - - for cidr, ip, mac in self._dhcp_mappings( - context, new_ips, mac): - self.client.add_dhcp_host( - bridge, cidr, ip, mac) - - if (self._check_update_deletes_security_groups(port) or - self._check_update_has_security_groups(port)): - self._unbind_port_from_sgs(context, p["id"]) - sg_ids = self._get_security_groups_on_port(context, port) - self._bind_port_to_sgs(context, p, sg_ids) - - self._process_portbindings_create_and_update(context, - port['port'], - p) - return p - - def create_router(self, context, router): - """Handle router creation. - - When a new Neutron router is created, its corresponding MidoNet router - is also created. In MidoNet, this router is initialized with chains - for inbound and outbound traffic, which will be used to hold other - chains that include various rules, such as NAT. - - :param router: Router information provided to create a new router. - """ - - # NOTE(dcahill): Similar to the NSX plugin, we completely override - # this method in order to be able to use the MidoNet ID as Neutron ID - # TODO(dcahill): Propose upstream patch for allowing - # 3rd parties to specify IDs as we do with l2 plugin - LOG.debug(_("MidonetPluginV2.create_router called: router=%(router)s"), - {"router": router}) - r = router['router'] - tenant_id = self._get_tenant_id_for_create(context, r) - r['tenant_id'] = tenant_id - mido_router = self.client.create_router(**r) - mido_router_id = mido_router.get_id() - - try: - has_gw_info = False - if EXTERNAL_GW_INFO in r: - has_gw_info = True - gw_info = r.pop(EXTERNAL_GW_INFO) - with context.session.begin(subtransactions=True): - # pre-generate id so it will be available when - # configuring external gw port - router_db = l3_db.Router(id=mido_router_id, - tenant_id=tenant_id, - name=r['name'], - admin_state_up=r['admin_state_up'], - status="ACTIVE") - context.session.add(router_db) - if has_gw_info: - self._update_router_gw_info(context, router_db['id'], - gw_info) - - router_data = self._make_router_dict(router_db) - - except Exception: - # Try removing the midonet router - with excutils.save_and_reraise_exception(): - self.client.delete_router(mido_router_id) - - # Create router chains - chain_names = _nat_chain_names(mido_router_id) - try: - self.client.add_router_chains(mido_router, - chain_names["pre-routing"], - chain_names["post-routing"]) - except Exception: - # Set the router status to Error - with context.session.begin(subtransactions=True): - r = self._get_router(context, router_data["id"]) - router_data['status'] = constants.NET_STATUS_ERROR - r['status'] = router_data['status'] - context.session.add(r) - - LOG.debug(_("MidonetPluginV2.create_router exiting: " - "router_data=%(router_data)s."), - {"router_data": router_data}) - return router_data - - def _set_router_gateway(self, id, gw_router, gw_ip): - """Set router uplink gateway - - :param ID: ID of the router - :param gw_router: gateway router to link to - :param gw_ip: gateway IP address - """ - LOG.debug(_("MidonetPluginV2.set_router_gateway called: id=%(id)s, " - "gw_router=%(gw_router)s, gw_ip=%(gw_ip)s"), - {'id': id, 'gw_router': gw_router, 'gw_ip': gw_ip}), - - router = self.client.get_router(id) - - # Create a port in the gw router - gw_port = self.client.add_router_port(gw_router, - port_address='169.254.255.1', - network_address='169.254.255.0', - network_length=30) - - # Create a port in the router - port = self.client.add_router_port(router, - port_address='169.254.255.2', - network_address='169.254.255.0', - network_length=30) - - # Link them - self.client.link(gw_port, port.get_id()) - - # Add a route for gw_ip to bring it down to the router - self.client.add_router_route(gw_router, type='Normal', - src_network_addr='0.0.0.0', - src_network_length=0, - dst_network_addr=gw_ip, - dst_network_length=32, - next_hop_port=gw_port.get_id(), - weight=100) - - # Add default route to uplink in the router - self.client.add_router_route(router, type='Normal', - src_network_addr='0.0.0.0', - src_network_length=0, - dst_network_addr='0.0.0.0', - dst_network_length=0, - next_hop_port=port.get_id(), - weight=100) - - def _remove_router_gateway(self, id): - """Clear router gateway - - :param ID: ID of the router - """ - LOG.debug(_("MidonetPluginV2.remove_router_gateway called: " - "id=%(id)s"), {'id': id}) - router = self.client.get_router(id) - - # delete the port that is connected to the gateway router - for p in router.get_ports(): - if p.get_port_address() == '169.254.255.2': - peer_port_id = p.get_peer_id() - if peer_port_id is not None: - self.client.unlink(p) - self.client.delete_port(peer_port_id) - - # delete default route - for r in router.get_routes(): - if (r.get_dst_network_addr() == '0.0.0.0' and - r.get_dst_network_length() == 0): - self.client.delete_route(r.get_id()) - - def update_router(self, context, id, router): - """Handle router updates.""" - LOG.debug(_("MidonetPluginV2.update_router called: id=%(id)s " - "router=%(router)r"), {"id": id, "router": router}) - - router_data = router["router"] - - # Check if the update included changes to the gateway. - gw_updated = l3_db.EXTERNAL_GW_INFO in router_data - with context.session.begin(subtransactions=True): - - # Update the Neutron DB - r = super(MidonetPluginV2, self).update_router(context, id, - router) - tenant_id = r["tenant_id"] - if gw_updated: - if (l3_db.EXTERNAL_GW_INFO in r and - r[l3_db.EXTERNAL_GW_INFO] is not None): - # Gateway created - gw_port_neutron = self._get_port( - context.elevated(), r["gw_port_id"]) - gw_ip = gw_port_neutron['fixed_ips'][0]['ip_address'] - - # First link routers and set up the routes - self._set_router_gateway(r["id"], - self._get_provider_router(), - gw_ip) - gw_port_midonet = self.client.get_link_port( - self._get_provider_router(), r["id"]) - - # Get the NAT chains and add dynamic SNAT rules. - chain_names = _nat_chain_names(r["id"]) - props = {OS_TENANT_ROUTER_RULE_KEY: SNAT_RULE} - self.client.add_dynamic_snat(tenant_id, - chain_names['pre-routing'], - chain_names['post-routing'], - gw_ip, - gw_port_midonet.get_id(), - **props) - - self.client.update_router(id, **router_data) - - LOG.debug(_("MidonetPluginV2.update_router exiting: router=%r"), r) - return r - - def delete_router(self, context, id): - """Handler for router deletion. - - Deleting a router on Neutron simply means deleting its corresponding - router in MidoNet. - - :param id: router ID to remove - """ - LOG.debug(_("MidonetPluginV2.delete_router called: id=%s"), id) - - self.client.delete_router_chains(id) - self.client.delete_router(id) - - super(MidonetPluginV2, self).delete_router(context, id) - - def _link_bridge_to_gw_router(self, bridge, gw_router, gw_ip, cidr): - """Link a bridge to the gateway router - - :param bridge: bridge - :param gw_router: gateway router to link to - :param gw_ip: IP address of gateway - :param cidr: network CIDR - """ - net_addr, net_len = net_util.net_addr(cidr) - - # create a port on the gateway router - gw_port = self.client.add_router_port(gw_router, port_address=gw_ip, - network_address=net_addr, - network_length=net_len) - - # create a bridge port, then link it to the router. - port = self.client.add_bridge_port(bridge) - self.client.link(gw_port, port.get_id()) - - # add a route for the subnet in the gateway router - self.client.add_router_route(gw_router, type='Normal', - src_network_addr='0.0.0.0', - src_network_length=0, - dst_network_addr=net_addr, - dst_network_length=net_len, - next_hop_port=gw_port.get_id(), - weight=100) - - def _unlink_bridge_from_gw_router(self, bridge, gw_router): - """Unlink a bridge from the gateway router - - :param bridge: bridge to unlink - :param gw_router: gateway router to unlink from - """ - # Delete routes and unlink the router and the bridge. - routes = self.client.get_router_routes(gw_router.get_id()) - - bridge_ports_to_delete = [ - p for p in gw_router.get_peer_ports() - if p.get_device_id() == bridge.get_id()] - - for p in bridge.get_peer_ports(): - if p.get_device_id() == gw_router.get_id(): - # delete the routes going to the bridge - for r in routes: - if r.get_next_hop_port() == p.get_id(): - self.client.delete_route(r.get_id()) - self.client.unlink(p) - self.client.delete_port(p.get_id()) - - # delete bridge port - for port in bridge_ports_to_delete: - self.client.delete_port(port.get_id()) - - def _link_bridge_to_router(self, router, bridge_port, net_addr, net_len, - gw_ip, metadata_gw_ip): - router_port = self.client.add_router_port( - router, network_length=net_len, network_address=net_addr, - port_address=gw_ip, admin_state_up=bridge_port['admin_state_up']) - self.client.link(router_port, bridge_port['id']) - self.client.add_router_route(router, type='Normal', - src_network_addr='0.0.0.0', - src_network_length=0, - dst_network_addr=net_addr, - dst_network_length=net_len, - next_hop_port=router_port.get_id(), - weight=100) - - if metadata_gw_ip: - # Add a route for the metadata server. - # Not all VM images supports DHCP option 121. Add a route for the - # Metadata server in the router to forward the packet to the bridge - # that will send them to the Metadata Proxy. - md_net_addr, md_net_len = net_util.net_addr(METADATA_DEFAULT_IP) - self.client.add_router_route( - router, type='Normal', src_network_addr=net_addr, - src_network_length=net_len, - dst_network_addr=md_net_addr, - dst_network_length=md_net_len, - next_hop_port=router_port.get_id(), - next_hop_gateway=metadata_gw_ip) - - def _unlink_bridge_from_router(self, router_id, bridge_port_id): - """Unlink a bridge from a router.""" - - # Remove the routes to the port and unlink the port - bridge_port = self.client.get_port(bridge_port_id) - routes = self.client.get_router_routes(router_id) - self.client.delete_port_routes(routes, bridge_port.get_peer_id()) - self.client.unlink(bridge_port) - - def add_router_interface(self, context, router_id, interface_info): - """Handle router linking with network.""" - LOG.debug(_("MidonetPluginV2.add_router_interface called: " - "router_id=%(router_id)s " - "interface_info=%(interface_info)r"), - {'router_id': router_id, 'interface_info': interface_info}) - - with context.session.begin(subtransactions=True): - info = super(MidonetPluginV2, self).add_router_interface( - context, router_id, interface_info) - - try: - subnet = self._get_subnet(context, info["subnet_id"]) - cidr = subnet["cidr"] - net_addr, net_len = net_util.net_addr(cidr) - router = self.client.get_router(router_id) - - # Get the metadata GW IP - metadata_gw_ip = None - rport_qry = context.session.query(models_v2.Port) - dhcp_ports = rport_qry.filter_by( - network_id=subnet["network_id"], - device_owner=constants.DEVICE_OWNER_DHCP).all() - if dhcp_ports and dhcp_ports[0].fixed_ips: - metadata_gw_ip = dhcp_ports[0].fixed_ips[0].ip_address - else: - LOG.warn(_("DHCP agent is not working correctly. No port " - "to reach the Metadata server on this network")) - # Link the router and the bridge - port = super(MidonetPluginV2, self).get_port(context, - info["port_id"]) - self._link_bridge_to_router(router, port, net_addr, - net_len, subnet["gateway_ip"], - metadata_gw_ip) - except Exception: - LOG.error(_("Failed to create MidoNet resources to add router " - "interface. info=%(info)s, router_id=%(router_id)s"), - {"info": info, "router_id": router_id}) - with excutils.save_and_reraise_exception(): - with context.session.begin(subtransactions=True): - self.remove_router_interface(context, router_id, info) - - LOG.debug(_("MidonetPluginV2.add_router_interface exiting: " - "info=%r"), info) - return info - - def _assoc_fip(self, fip): - router = self.client.get_router(fip["router_id"]) - link_port = self.client.get_link_port( - self._get_provider_router(), router.get_id()) - self.client.add_router_route( - self._get_provider_router(), - src_network_addr='0.0.0.0', - src_network_length=0, - dst_network_addr=fip["floating_ip_address"], - dst_network_length=32, - next_hop_port=link_port.get_peer_id()) - props = {OS_FLOATING_IP_RULE_KEY: fip['id']} - tenant_id = router.get_tenant_id() - chain_names = _nat_chain_names(router.get_id()) - for chain_type, name in chain_names.items(): - src_ip, target_ip = _get_nat_ips(chain_type, fip) - if chain_type == 'pre-routing': - nat_type = 'dnat' - else: - nat_type = 'snat' - self.client.add_static_nat(tenant_id, name, src_ip, - target_ip, - link_port.get_id(), - nat_type, **props) - - def create_floatingip(self, context, floatingip): - session = context.session - with session.begin(subtransactions=True): - fip = super(MidonetPluginV2, self).create_floatingip( - context, floatingip) - if fip['port_id']: - self._assoc_fip(fip) - return fip - - def update_floatingip(self, context, id, floatingip): - """Handle floating IP association and disassociation.""" - LOG.debug(_("MidonetPluginV2.update_floatingip called: id=%(id)s " - "floatingip=%(floatingip)s "), - {'id': id, 'floatingip': floatingip}) - - session = context.session - with session.begin(subtransactions=True): - if floatingip['floatingip']['port_id']: - fip = super(MidonetPluginV2, self).update_floatingip( - context, id, floatingip) - - self._assoc_fip(fip) - - # disassociate floating IP - elif floatingip['floatingip']['port_id'] is None: - fip = super(MidonetPluginV2, self).get_floatingip(context, id) - self._remove_nat_rules(context, fip) - super(MidonetPluginV2, self).update_floatingip(context, id, - floatingip) - - LOG.debug(_("MidonetPluginV2.update_floating_ip exiting: fip=%s"), fip) - return fip - - def disassociate_floatingips(self, context, port_id): - """Disassociate floating IPs (if any) from this port.""" - try: - fip_qry = context.session.query(l3_db.FloatingIP) - fip_dbs = fip_qry.filter_by(fixed_port_id=port_id) - for fip_db in fip_dbs: - self._remove_nat_rules(context, fip_db) - except sa_exc.NoResultFound: - pass - - super(MidonetPluginV2, self).disassociate_floatingips(context, port_id) - - def create_security_group(self, context, security_group, default_sg=False): - """Create security group. - - Create a new security group, including the default security group. - In MidoNet, this means creating a pair of chains, inbound and outbound, - as well as a new port group. - """ - LOG.debug(_("MidonetPluginV2.create_security_group called: " - "security_group=%(security_group)s " - "default_sg=%(default_sg)s "), - {'security_group': security_group, 'default_sg': default_sg}) - - sg = security_group.get('security_group') - tenant_id = self._get_tenant_id_for_create(context, sg) - if not default_sg: - self._ensure_default_security_group(context, tenant_id) - - # Create the Neutron sg first - sg = super(MidonetPluginV2, self).create_security_group( - context, security_group, default_sg) - - try: - # Process the MidoNet side - self.client.create_port_group(tenant_id, - _sg_port_group_name(sg["id"])) - chain_names = _sg_chain_names(sg["id"]) - chains = {} - for direction, chain_name in chain_names.iteritems(): - c = self.client.create_chain(tenant_id, chain_name) - chains[direction] = c - - # Create all the rules for this SG. Only accept rules are created - for r in sg['security_group_rules']: - self._create_accept_chain_rule(context, r, - chain=chains[r['direction']]) - except Exception: - LOG.error(_("Failed to create MidoNet resources for sg %(sg)r"), - {"sg": sg}) - with excutils.save_and_reraise_exception(): - with context.session.begin(subtransactions=True): - sg = self._get_security_group(context, sg["id"]) - context.session.delete(sg) - - LOG.debug(_("MidonetPluginV2.create_security_group exiting: sg=%r"), - sg) - return sg - - def delete_security_group(self, context, id): - """Delete chains for Neutron security group.""" - LOG.debug(_("MidonetPluginV2.delete_security_group called: id=%s"), id) - - with context.session.begin(subtransactions=True): - sg = super(MidonetPluginV2, self).get_security_group(context, id) - if not sg: - raise ext_sg.SecurityGroupNotFound(id=id) - - if sg["name"] == 'default' and not context.is_admin: - raise ext_sg.SecurityGroupCannotRemoveDefault() - - sg_id = sg['id'] - filters = {'security_group_id': [sg_id]} - if super(MidonetPluginV2, self)._get_port_security_group_bindings( - context, filters): - raise ext_sg.SecurityGroupInUse(id=sg_id) - - # Delete MidoNet Chains and portgroup for the SG - tenant_id = sg['tenant_id'] - self.client.delete_chains_by_names( - tenant_id, _sg_chain_names(sg["id"]).values()) - - self.client.delete_port_group_by_name( - tenant_id, _sg_port_group_name(sg["id"])) - - super(MidonetPluginV2, self).delete_security_group(context, id) - - def create_security_group_rule(self, context, security_group_rule): - """Create a security group rule - - Create a security group rule in the Neutron DB and corresponding - MidoNet resources in its data store. - """ - LOG.debug(_("MidonetPluginV2.create_security_group_rule called: " - "security_group_rule=%(security_group_rule)r"), - {'security_group_rule': security_group_rule}) - - with context.session.begin(subtransactions=True): - rule = super(MidonetPluginV2, self).create_security_group_rule( - context, security_group_rule) - - self._create_accept_chain_rule(context, rule) - - LOG.debug(_("MidonetPluginV2.create_security_group_rule exiting: " - "rule=%r"), rule) - return rule - - def delete_security_group_rule(self, context, sg_rule_id): - """Delete a security group rule - - Delete a security group rule from the Neutron DB and corresponding - MidoNet resources from its data store. - """ - LOG.debug(_("MidonetPluginV2.delete_security_group_rule called: " - "sg_rule_id=%s"), sg_rule_id) - with context.session.begin(subtransactions=True): - rule = super(MidonetPluginV2, self).get_security_group_rule( - context, sg_rule_id) - - if not rule: - raise ext_sg.SecurityGroupRuleNotFound(id=sg_rule_id) - - sg = self._get_security_group(context, - rule["security_group_id"]) - chain_name = _sg_chain_names(sg["id"])[rule["direction"]] - self.client.remove_rules_by_property(rule["tenant_id"], chain_name, - OS_SG_RULE_KEY, - str(rule["id"])) - super(MidonetPluginV2, self).delete_security_group_rule( - context, sg_rule_id) - - def _add_chain_rule(self, chain, action, **kwargs): - - nw_proto = kwargs.get("nw_proto") - src_addr = kwargs.pop("src_addr", None) - dst_addr = kwargs.pop("dst_addr", None) - src_port_from = kwargs.pop("src_port_from", None) - src_port_to = kwargs.pop("src_port_to", None) - dst_port_from = kwargs.pop("dst_port_from", None) - dst_port_to = kwargs.pop("dst_port_to", None) - - # Convert to the keys and values that midonet client understands - if src_addr: - kwargs["nw_src_addr"], kwargs["nw_src_length"] = net_util.net_addr( - src_addr) - - if dst_addr: - kwargs["nw_dst_addr"], kwargs["nw_dst_length"] = net_util.net_addr( - dst_addr) - - kwargs["tp_src"] = {"start": src_port_from, "end": src_port_to} - - kwargs["tp_dst"] = {"start": dst_port_from, "end": dst_port_to} - - if nw_proto == 1: # ICMP - # Overwrite port fields regardless of the direction - kwargs["tp_src"] = {"start": src_port_from, "end": src_port_from} - kwargs["tp_dst"] = {"start": dst_port_to, "end": dst_port_to} - - return self.client.add_chain_rule(chain, action=action, **kwargs) diff --git a/neutron/plugins/ml2/README b/neutron/plugins/ml2/README deleted file mode 100644 index 4dce789cb..000000000 --- a/neutron/plugins/ml2/README +++ /dev/null @@ -1,53 +0,0 @@ -The Modular Layer 2 (ML2) plugin is a framework allowing OpenStack -Networking to simultaneously utilize the variety of layer 2 networking -technologies found in complex real-world data centers. It supports the -Open vSwitch, Linux bridge, and Hyper-V L2 agents, replacing and -deprecating the monolithic plugins previously associated with those -agents, and can also support hardware devices and SDN controllers. The -ML2 framework is intended to greatly simplify adding support for new -L2 networking technologies, requiring much less initial and ongoing -effort than would be required for an additional monolithic core -plugin. It is also intended to foster innovation through its -organization as optional driver modules. - -The ML2 plugin supports all the non-vendor-specific neutron API -extensions, and works with the standard neutron DHCP agent. It -utilizes the service plugin interface to implement the L3 router -abstraction, allowing use of either the standard neutron L3 agent or -alternative L3 solutions. Additional service plugins can also be used -with the ML2 core plugin. - -Drivers within ML2 implement separately extensible sets of network -types and of mechanisms for accessing networks of those types. Unlike -with the metaplugin, multiple mechanisms can be used simultaneously to -access different ports of the same virtual network. Mechanisms can -utilize L2 agents via RPC and/or interact with external devices or -controllers. By utilizing the multiprovidernet extension, virtual -networks can be composed of multiple segments of the same or different -types. Type and mechanism drivers are loaded as python entrypoints -using the stevedore library. - -Each available network type is managed by an ML2 type driver. Type -drivers maintain any needed type-specific network state, and perform -provider network validation and tenant network allocation. As of the -havana release, drivers for the local, flat, vlan, gre, and vxlan -network types are included. - -Each available networking mechanism is managed by an ML2 mechanism -driver. All registered mechanism drivers are called twice when -networks, subnets, and ports are created, updated, or deleted. They -are first called as part of the DB transaction, where they can -maintain any needed driver-specific state. Once the transaction has -been committed, they are called again, at which point they can -interact with external devices and controllers. Mechanism drivers are -also called as part of the port binding process, to determine whether -the associated mechanism can provide connectivity for the network, and -if so, the network segment and VIF driver to be used. The havana -release includes mechanism drivers for the Open vSwitch, Linux bridge, -and Hyper-V L2 agents, for Arista and Cisco switches, and for the -Tail-f NCS. It also includes an L2 Population mechanism driver that -can help optimize tunneled virtual network traffic. - -For additional information regarding the ML2 plugin and its collection -of type and mechanism drivers, see the OpenStack manuals and -http://wiki.openstack.org/wiki/Neutron/ML2. diff --git a/neutron/plugins/ml2/__init__.py b/neutron/plugins/ml2/__init__.py deleted file mode 100644 index 788cea1f7..000000000 --- a/neutron/plugins/ml2/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2013 OpenStack Foundation -# 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. diff --git a/neutron/plugins/ml2/common/__init__.py b/neutron/plugins/ml2/common/__init__.py deleted file mode 100644 index 788cea1f7..000000000 --- a/neutron/plugins/ml2/common/__init__.py +++ /dev/null @@ -1,14 +0,0 @@ -# Copyright (c) 2013 OpenStack Foundation -# 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. diff --git a/neutron/plugins/ml2/common/exceptions.py b/neutron/plugins/ml2/common/exceptions.py deleted file mode 100644 index ed94b1e1f..000000000 --- a/neutron/plugins/ml2/common/exceptions.py +++ /dev/null @@ -1,23 +0,0 @@ -# Copyright (c) 2013 OpenStack Foundation -# 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. - -"""Exceptions used by ML2.""" - -from neutron.common import exceptions - - -class MechanismDriverError(exceptions.NeutronException): - """Mechanism driver call failed.""" - message = _("%(method)s failed.") diff --git a/neutron/plugins/ml2/config.py b/neutron/plugins/ml2/config.py deleted file mode 100644 index afce63045..000000000 --- a/neutron/plugins/ml2/config.py +++ /dev/null @@ -1,36 +0,0 @@ -# Copyright (c) 2013 OpenStack Foundation -# 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 oslo.config import cfg - - -ml2_opts = [ - cfg.ListOpt('type_drivers', - default=['local', 'flat', 'vlan', 'gre', 'vxlan'], - help=_("List of network type driver entrypoints to be loaded " - "from the neutron.ml2.type_drivers namespace.")), - cfg.ListOpt('tenant_network_types', - default=['local'], - help=_("Ordered list of network_types to allocate as tenant " - "networks.")), - cfg.ListOpt('mechanism_drivers', - default=[], - help=_("An ordered list of networking mechanism driver " - "entrypoints to be loaded from the " - "neutron.ml2.mechanism_drivers namespace.")), -] - - -cfg.CONF.register_opts(ml2_opts, "ml2") diff --git a/neutron/plugins/ml2/db.py b/neutron/plugins/ml2/db.py deleted file mode 100644 index 4cf8eed32..000000000 --- a/neutron/plugins/ml2/db.py +++ /dev/null @@ -1,136 +0,0 @@ -# Copyright (c) 2013 OpenStack Foundation -# 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 sqlalchemy.orm import exc - -from neutron.db import api as db_api -from neutron.db import models_v2 -from neutron.db import securitygroups_db as sg_db -from neutron.extensions import portbindings -from neutron import manager -from neutron.openstack.common import log -from neutron.openstack.common import uuidutils -from neutron.plugins.ml2 import driver_api as api -from neutron.plugins.ml2 import models - -LOG = log.getLogger(__name__) - - -def add_network_segment(session, network_id, segment): - with session.begin(subtransactions=True): - record = models.NetworkSegment( - id=uuidutils.generate_uuid(), - network_id=network_id, - network_type=segment.get(api.NETWORK_TYPE), - physical_network=segment.get(api.PHYSICAL_NETWORK), - segmentation_id=segment.get(api.SEGMENTATION_ID) - ) - session.add(record) - LOG.info(_("Added segment %(id)s of type %(network_type)s for network" - " %(network_id)s"), - {'id': record.id, - 'network_type': record.network_type, - 'network_id': record.network_id}) - - -def get_network_segments(session, network_id): - with session.begin(subtransactions=True): - records = (session.query(models.NetworkSegment). - filter_by(network_id=network_id)) - return [{api.ID: record.id, - api.NETWORK_TYPE: record.network_type, - api.PHYSICAL_NETWORK: record.physical_network, - api.SEGMENTATION_ID: record.segmentation_id} - for record in records] - - -def ensure_port_binding(session, port_id): - with session.begin(subtransactions=True): - try: - record = (session.query(models.PortBinding). - filter_by(port_id=port_id). - one()) - except exc.NoResultFound: - record = models.PortBinding( - port_id=port_id, - vif_type=portbindings.VIF_TYPE_UNBOUND) - session.add(record) - return record - - -def get_port(session, port_id): - """Get port record for update within transcation.""" - - with session.begin(subtransactions=True): - try: - record = (session.query(models_v2.Port). - filter(models_v2.Port.id.startswith(port_id)). - one()) - return record - except exc.NoResultFound: - return - except exc.MultipleResultsFound: - LOG.error(_("Multiple ports have port_id starting with %s"), - port_id) - return - - -def get_port_from_device_mac(device_mac): - LOG.debug(_("get_port_from_device_mac() called for mac %s"), device_mac) - session = db_api.get_session() - qry = session.query(models_v2.Port).filter_by(mac_address=device_mac) - return qry.first() - - -def get_port_and_sgs(port_id): - """Get port from database with security group info.""" - - LOG.debug(_("get_port_and_sgs() called for port_id %s"), port_id) - session = db_api.get_session() - sg_binding_port = sg_db.SecurityGroupPortBinding.port_id - - with session.begin(subtransactions=True): - query = session.query(models_v2.Port, - sg_db.SecurityGroupPortBinding.security_group_id) - query = query.outerjoin(sg_db.SecurityGroupPortBinding, - models_v2.Port.id == sg_binding_port) - query = query.filter(models_v2.Port.id.startswith(port_id)) - port_and_sgs = query.all() - if not port_and_sgs: - return - port = port_and_sgs[0][0] - plugin = manager.NeutronManager.get_plugin() - port_dict = plugin._make_port_dict(port) - port_dict['security_groups'] = [ - sg_id for port_, sg_id in port_and_sgs if sg_id] - port_dict['security_group_rules'] = [] - port_dict['security_group_source_groups'] = [] - port_dict['fixed_ips'] = [ip['ip_address'] - for ip in port['fixed_ips']] - return port_dict - - -def get_port_binding_host(port_id): - session = db_api.get_session() - with session.begin(subtransactions=True): - try: - query = (session.query(models.PortBinding). - filter(models.PortBinding.port_id.startswith(port_id)). - one()) - except exc.NoResultFound: - LOG.debug(_("No binding found for port %(port_id)s"), - {'port_id': port_id}) - return - return query.host diff --git a/neutron/plugins/ml2/driver_api.py b/neutron/plugins/ml2/driver_api.py deleted file mode 100644 index 2384b0cf9..000000000 --- a/neutron/plugins/ml2/driver_api.py +++ /dev/null @@ -1,597 +0,0 @@ -# Copyright (c) 2013 OpenStack Foundation -# 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. - -import abc -import six - -# The following keys are used in the segment dictionaries passed via -# the driver API. These are defined separately from similar keys in -# neutron.extensions.providernet so that drivers don't need to change -# if/when providernet moves to the core API. -# -ID = 'id' -NETWORK_TYPE = 'network_type' -PHYSICAL_NETWORK = 'physical_network' -SEGMENTATION_ID = 'segmentation_id' - - -@six.add_metaclass(abc.ABCMeta) -class TypeDriver(object): - """Define stable abstract interface for ML2 type drivers. - - ML2 type drivers each support a specific network_type for provider - and/or tenant network segments. Type drivers must implement this - abstract interface, which defines the API by which the plugin uses - the driver to manage the persistent type-specific resource - allocation state associated with network segments of that type. - - Network segments are represented by segment dictionaries using the - NETWORK_TYPE, PHYSICAL_NETWORK, and SEGMENTATION_ID keys defined - above, corresponding to the provider attributes. Future revisions - of the TypeDriver API may add additional segment dictionary - keys. Attributes not applicable for a particular network_type may - either be excluded or stored as None. - """ - - @abc.abstractmethod - def get_type(self): - """Get driver's network type. - - :returns network_type value handled by this driver - """ - pass - - @abc.abstractmethod - def initialize(self): - """Perform driver initialization. - - Called after all drivers have been loaded and the database has - been initialized. No abstract methods defined below will be - called prior to this method being called. - """ - pass - - @abc.abstractmethod - def validate_provider_segment(self, segment): - """Validate attributes of a provider network segment. - - :param segment: segment dictionary using keys defined above - :raises: neutron.common.exceptions.InvalidInput if invalid - - Called outside transaction context to validate the provider - attributes for a provider network segment. Raise InvalidInput - if: - - - any required attribute is missing - - any prohibited or unrecognized attribute is present - - any attribute value is not valid - - The network_type attribute is present in segment, but - need not be validated. - """ - pass - - @abc.abstractmethod - def reserve_provider_segment(self, session, segment): - """Reserve resource associated with a provider network segment. - - :param session: database session - :param segment: segment dictionary using keys defined above - - Called inside transaction context on session to reserve the - type-specific resource for a provider network segment. The - segment dictionary passed in was returned by a previous - validate_provider_segment() call. - """ - pass - - @abc.abstractmethod - def allocate_tenant_segment(self, session): - """Allocate resource for a new tenant network segment. - - :param session: database session - :returns: segment dictionary using keys defined above - - Called inside transaction context on session to allocate a new - tenant network, typically from a type-specific resource - pool. If successful, return a segment dictionary describing - the segment. If tenant network segment cannot be allocated - (i.e. tenant networks not supported or resource pool is - exhausted), return None. - """ - pass - - @abc.abstractmethod - def release_segment(self, session, segment): - """Release network segment. - - :param session: database session - :param segment: segment dictionary using keys defined above - - Called inside transaction context on session to release a - tenant or provider network's type-specific resource. Runtime - errors are not expected, but raising an exception will result - in rollback of the transaction. - """ - pass - - -@six.add_metaclass(abc.ABCMeta) -class NetworkContext(object): - """Context passed to MechanismDrivers for changes to network resources. - - A NetworkContext instance wraps a network resource. It provides - helper methods for accessing other relevant information. Results - from expensive operations are cached so that other - MechanismDrivers can freely access the same information. - """ - - @abc.abstractproperty - def current(self): - """Return the current state of the network. - - Return the current state of the network, as defined by - NeutronPluginBaseV2.create_network and all extensions in the - ml2 plugin. - """ - pass - - @abc.abstractproperty - def original(self): - """Return the original state of the network. - - Return the original state of the network, prior to a call to - update_network. Method is only valid within calls to - update_network_precommit and update_network_postcommit. - """ - pass - - @abc.abstractproperty - def network_segments(self): - """Return the segments associated with this network resource.""" - pass - - -@six.add_metaclass(abc.ABCMeta) -class SubnetContext(object): - """Context passed to MechanismDrivers for changes to subnet resources. - - A SubnetContext instance wraps a subnet resource. It provides - helper methods for accessing other relevant information. Results - from expensive operations are cached so that other - MechanismDrivers can freely access the same information. - """ - - @abc.abstractproperty - def current(self): - """Return the current state of the subnet. - - Return the current state of the subnet, as defined by - NeutronPluginBaseV2.create_subnet and all extensions in the - ml2 plugin. - """ - pass - - @abc.abstractproperty - def original(self): - """Return the original state of the subnet. - - Return the original state of the subnet, prior to a call to - update_subnet. Method is only valid within calls to - update_subnet_precommit and update_subnet_postcommit. - """ - pass - - -@six.add_metaclass(abc.ABCMeta) -class PortContext(object): - """Context passed to MechanismDrivers for changes to port resources. - - A PortContext instance wraps a port resource. It provides helper - methods for accessing other relevant information. Results from - expensive operations are cached so that other MechanismDrivers can - freely access the same information. - """ - - @abc.abstractproperty - def current(self): - """Return the current state of the port. - - Return the current state of the port, as defined by - NeutronPluginBaseV2.create_port and all extensions in the ml2 - plugin. - """ - pass - - @abc.abstractproperty - def original(self): - """Return the original state of the port. - - Return the original state of the port, prior to a call to - update_port. Method is only valid within calls to - update_port_precommit and update_port_postcommit. - """ - pass - - @abc.abstractproperty - def network(self): - """Return the NetworkContext associated with this port.""" - pass - - @abc.abstractproperty - def bound_segment(self): - """Return the currently bound segment dictionary.""" - pass - - @abc.abstractproperty - def original_bound_segment(self): - """Return the original bound segment dictionary. - - Return the original bound segment dictionary, prior to a call - to update_port. Method is only valid within calls to - update_port_precommit and update_port_postcommit. - """ - pass - - @abc.abstractproperty - def bound_driver(self): - """Return the currently bound mechanism driver name.""" - pass - - @abc.abstractproperty - def original_bound_driver(self): - """Return the original bound mechanism driver name. - - Return the original bound mechanism driver name, prior to a - call to update_port. Method is only valid within calls to - update_port_precommit and update_port_postcommit. - """ - pass - - @abc.abstractmethod - def host_agents(self, agent_type): - """Get agents of the specified type on port's host. - - :param agent_type: Agent type identifier - :returns: List of agents_db.Agent records - """ - pass - - @abc.abstractmethod - def set_binding(self, segment_id, vif_type, vif_details, - status=None): - """Set the binding for the port. - - :param segment_id: Network segment bound for the port. - :param vif_type: The VIF type for the bound port. - :param vif_details: Dictionary with details for VIF driver. - :param status: Port status to set if not None. - - Called by MechanismDriver.bind_port to indicate success and - specify binding details to use for port. The segment_id must - identify an item in network.network_segments. - """ - pass - - -@six.add_metaclass(abc.ABCMeta) -class MechanismDriver(object): - """Define stable abstract interface for ML2 mechanism drivers. - - A mechanism driver is called on the creation, update, and deletion - of networks and ports. For every event, there are two methods that - get called - one within the database transaction (method suffix of - _precommit), one right afterwards (method suffix of _postcommit). - - Exceptions raised by methods called inside the transaction can - rollback, but should not make any blocking calls (for example, - REST requests to an outside controller). Methods called after - transaction commits can make blocking external calls, though these - will block the entire process. Exceptions raised in calls after - the transaction commits may cause the associated resource to be - deleted. - - Because rollback outside of the transaction is not done in the - update network/port case, all data validation must be done within - methods that are part of the database transaction. - """ - - @abc.abstractmethod - def initialize(self): - """Perform driver initialization. - - Called after all drivers have been loaded and the database has - been initialized. No abstract methods defined below will be - called prior to this method being called. - """ - pass - - def create_network_precommit(self, context): - """Allocate resources for a new network. - - :param context: NetworkContext instance describing the new - network. - - Create a new network, allocating resources as necessary in the - database. Called inside transaction context on session. Call - cannot block. Raising an exception will result in a rollback - of the current transaction. - """ - pass - - def create_network_postcommit(self, context): - """Create a network. - - :param context: NetworkContext instance describing the new - network. - - Called after the transaction commits. Call can block, though - will block the entire process so care should be taken to not - drastically affect performance. Raising an exception will - cause the deletion of the resource. - """ - pass - - def update_network_precommit(self, context): - """Update resources of a network. - - :param context: NetworkContext instance describing the new - state of the network, as well as the original state prior - to the update_network call. - - Update values of a network, updating the associated resources - in the database. Called inside transaction context on session. - Raising an exception will result in rollback of the - transaction. - - update_network_precommit is called for all changes to the - network state. It is up to the mechanism driver to ignore - state or state changes that it does not know or care about. - """ - pass - - def update_network_postcommit(self, context): - """Update a network. - - :param context: NetworkContext instance describing the new - state of the network, as well as the original state prior - to the update_network call. - - Called after the transaction commits. Call can block, though - will block the entire process so care should be taken to not - drastically affect performance. Raising an exception will - cause the deletion of the resource. - - update_network_postcommit is called for all changes to the - network state. It is up to the mechanism driver to ignore - state or state changes that it does not know or care about. - """ - pass - - def delete_network_precommit(self, context): - """Delete resources for a network. - - :param context: NetworkContext instance describing the current - state of the network, prior to the call to delete it. - - Delete network resources previously allocated by this - mechanism driver for a network. Called inside transaction - context on session. Runtime errors are not expected, but - raising an exception will result in rollback of the - transaction. - """ - pass - - def delete_network_postcommit(self, context): - """Delete a network. - - :param context: NetworkContext instance describing the current - state of the network, prior to the call to delete it. - - Called after the transaction commits. Call can block, though - will block the entire process so care should be taken to not - drastically affect performance. Runtime errors are not - expected, and will not prevent the resource from being - deleted. - """ - pass - - def create_subnet_precommit(self, context): - """Allocate resources for a new subnet. - - :param context: SubnetContext instance describing the new - subnet. - - Create a new subnet, allocating resources as necessary in the - database. Called inside transaction context on session. Call - cannot block. Raising an exception will result in a rollback - of the current transaction. - """ - pass - - def create_subnet_postcommit(self, context): - """Create a subnet. - - :param context: SubnetContext instance describing the new - subnet. - - Called after the transaction commits. Call can block, though - will block the entire process so care should be taken to not - drastically affect performance. Raising an exception will - cause the deletion of the resource. - """ - pass - - def update_subnet_precommit(self, context): - """Update resources of a subnet. - - :param context: SubnetContext instance describing the new - state of the subnet, as well as the original state prior - to the update_subnet call. - - Update values of a subnet, updating the associated resources - in the database. Called inside transaction context on session. - Raising an exception will result in rollback of the - transaction. - - update_subnet_precommit is called for all changes to the - subnet state. It is up to the mechanism driver to ignore - state or state changes that it does not know or care about. - """ - pass - - def update_subnet_postcommit(self, context): - """Update a subnet. - - :param context: SubnetContext instance describing the new - state of the subnet, as well as the original state prior - to the update_subnet call. - - Called after the transaction commits. Call can block, though - will block the entire process so care should be taken to not - drastically affect performance. Raising an exception will - cause the deletion of the resource. - - update_subnet_postcommit is called for all changes to the - subnet state. It is up to the mechanism driver to ignore - state or state changes that it does not know or care about. - """ - pass - - def delete_subnet_precommit(self, context): - """Delete resources for a subnet. - - :param context: SubnetContext instance describing the current - state of the subnet, prior to the call to delete it. - - Delete subnet resources previously allocated by this - mechanism driver for a subnet. Called inside transaction - context on session. Runtime errors are not expected, but - raising an exception will result in rollback of the - transaction. - """ - pass - - def delete_subnet_postcommit(self, context): - """Delete a subnet. - - :param context: SubnetContext instance describing the current - state of the subnet, prior to the call to delete it. - - Called after the transaction commits. Call can block, though - will block the entire process so care should be taken to not - drastically affect performance. Runtime errors are not - expected, and will not prevent the resource from being - deleted. - """ - pass - - def create_port_precommit(self, context): - """Allocate resources for a new port. - - :param context: PortContext instance describing the port. - - Create a new port, allocating resources as necessary in the - database. Called inside transaction context on session. Call - cannot block. Raising an exception will result in a rollback - of the current transaction. - """ - pass - - def create_port_postcommit(self, context): - """Create a port. - - :param context: PortContext instance describing the port. - - Called after the transaction completes. Call can block, though - will block the entire process so care should be taken to not - drastically affect performance. Raising an exception will - result in the deletion of the resource. - """ - pass - - def update_port_precommit(self, context): - """Update resources of a port. - - :param context: PortContext instance describing the new - state of the port, as well as the original state prior - to the update_port call. - - Called inside transaction context on session to complete a - port update as defined by this mechanism driver. Raising an - exception will result in rollback of the transaction. - - update_port_precommit is called for all changes to the port - state. It is up to the mechanism driver to ignore state or - state changes that it does not know or care about. - """ - pass - - def update_port_postcommit(self, context): - """Update a port. - - :param context: PortContext instance describing the new - state of the port, as well as the original state prior - to the update_port call. - - Called after the transaction completes. Call can block, though - will block the entire process so care should be taken to not - drastically affect performance. Raising an exception will - result in the deletion of the resource. - - update_port_postcommit is called for all changes to the port - state. It is up to the mechanism driver to ignore state or - state changes that it does not know or care about. - """ - pass - - def delete_port_precommit(self, context): - """Delete resources of a port. - - :param context: PortContext instance describing the current - state of the port, prior to the call to delete it. - - Called inside transaction context on session. Runtime errors - are not expected, but raising an exception will result in - rollback of the transaction. - """ - pass - - def delete_port_postcommit(self, context): - """Delete a port. - - :param context: PortContext instance describing the current - state of the port, prior to the call to delete it. - - Called after the transaction completes. Call can block, though - will block the entire process so care should be taken to not - drastically affect performance. Runtime errors are not - expected, and will not prevent the resource from being - deleted. - """ - pass - - def bind_port(self, context): - """Attempt to bind a port. - - :param context: PortContext instance describing the port - - Called inside transaction context on session, prior to - create_port_precommit or update_port_precommit, to - attempt to establish a port binding. If the driver is able to - bind the port, it calls context.set_binding with the binding - details. - """ - pass diff --git a/neutron/plugins/ml2/driver_context.py b/neutron/plugins/ml2/driver_context.py deleted file mode 100644 index 0c1180619..000000000 --- a/neutron/plugins/ml2/driver_context.py +++ /dev/null @@ -1,135 +0,0 @@ -# Copyright (c) 2013 OpenStack Foundation -# 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 neutron.openstack.common import jsonutils -from neutron.plugins.ml2 import db -from neutron.plugins.ml2 import driver_api as api - - -class MechanismDriverContext(object): - """MechanismDriver context base class.""" - def __init__(self, plugin, plugin_context): - self._plugin = plugin - # This temporarily creates a reference loop, but the - # lifetime of PortContext is limited to a single - # method call of the plugin. - self._plugin_context = plugin_context - - -class NetworkContext(MechanismDriverContext, api.NetworkContext): - - def __init__(self, plugin, plugin_context, network, - original_network=None): - super(NetworkContext, self).__init__(plugin, plugin_context) - self._network = network - self._original_network = original_network - self._segments = db.get_network_segments(plugin_context.session, - network['id']) - - @property - def current(self): - return self._network - - @property - def original(self): - return self._original_network - - @property - def network_segments(self): - return self._segments - - -class SubnetContext(MechanismDriverContext, api.SubnetContext): - - def __init__(self, plugin, plugin_context, subnet, original_subnet=None): - super(SubnetContext, self).__init__(plugin, plugin_context) - self._subnet = subnet - self._original_subnet = original_subnet - - @property - def current(self): - return self._subnet - - @property - def original(self): - return self._original_subnet - - -class PortContext(MechanismDriverContext, api.PortContext): - - def __init__(self, plugin, plugin_context, port, network, - original_port=None): - super(PortContext, self).__init__(plugin, plugin_context) - self._port = port - self._original_port = original_port - self._network_context = NetworkContext(plugin, plugin_context, - network) - self._binding = db.ensure_port_binding(plugin_context.session, - port['id']) - if original_port: - self._original_bound_segment_id = self._binding.segment - self._original_bound_driver = self._binding.driver - else: - self._original_bound_segment_id = None - self._original_bound_driver = None - self._new_port_status = None - - @property - def current(self): - return self._port - - @property - def original(self): - return self._original_port - - @property - def network(self): - return self._network_context - - @property - def bound_segment(self): - id = self._binding.segment - if id: - for segment in self._network_context.network_segments: - if segment[api.ID] == id: - return segment - - @property - def original_bound_segment(self): - if self._original_bound_segment_id: - for segment in self._network_context.network_segments: - if segment[api.ID] == self._original_bound_segment_id: - return segment - - @property - def bound_driver(self): - return self._binding.driver - - @property - def original_bound_driver(self): - return self._original_bound_driver - - def host_agents(self, agent_type): - return self._plugin.get_agents(self._plugin_context, - filters={'agent_type': [agent_type], - 'host': [self._binding.host]}) - - def set_binding(self, segment_id, vif_type, vif_details, - status=None): - # TODO(rkukura) Verify binding allowed, segment in network - self._binding.segment = segment_id - self._binding.vif_type = vif_type - self._binding.vif_details = jsonutils.dumps(vif_details) - self._new_port_status = status diff --git a/neutron/plugins/ml2/drivers/README.fslsdn b/neutron/plugins/ml2/drivers/README.fslsdn deleted file mode 100644 index 09017284c..000000000 --- a/neutron/plugins/ml2/drivers/README.fslsdn +++ /dev/null @@ -1,102 +0,0 @@ -===================================================== -Freescale SDN Mechanism Driver for Neutron ML2 plugin -===================================================== - -Introduction -============ - -Freescale SDN (FSL-SDN) Mechanism Driver is an add-on support for ML2 plugin -for Neutron. - -It supports the Cloud Resource Discovery (CRD) service by updating -Network, Subnet and Port Create/Update/Delete data into the CRD database. - -CRD service manages network nodes, virtual network appliances and openflow -controller based network applications. - -Basic work flow ---------------- - -:: - - +---------------------------------+ - | | - | Neutron Server | - | (with ML2 plugin) | - | | - | +-------------------------------+ - | | Freescale SDN | - | | Mechanism Driver | - +-+--------+----------------------+ - | - | ReST API - | - +----------+-------------+ - | CRD server | - +------------------------+ - - - -How does Freescale SDN Mechanism Driver work? -=========================================== - -- Freescale Mechanism driver handles the following postcommit operations. - - Network create/update/delete - - Subnet create/update/delete - - Port create/delete - -Sequence diagram : create_network ---------------------------------- - -:: - - create_network - { - neutron -> ML2_plugin - ML2_plugin -> FSL-SDN-MD - FSL-SDN-MD -> crd_service - FSL-SDN-MD <-- crd_service - ML2_plugin <-- FSL-SDN-MD - neutron <-- ML2_plugin - } - -- Supported network types by FSL OF Controller include vlan and vxlan. - -- Freescale SDN mechanism driver handles VM port binding within in the - mechanism driver (like ODL MD). - -- 'bind_port' function verifies the supported network types (vlan,vxlan) - and calls context.set_binding with binding details. - -- Flow management in OVS is handled by Freescale Openflow Controller. - - -How to use Freescale SDN Mechanism Driver? -========================================== - -Configuring ML