From a9d3e5e8764fcedcafe355ad0a0733dc91594876 Mon Sep 17 00:00:00 2001
From: Ralf Haferkamp <rhafer@suse.de>
Date: Fri, 26 Feb 2016 15:47:49 +0100
Subject: [PATCH] Fix database attributes of the floating network and its
 router port (bsc#967009)

Because of several bugs (at least bsc#946882 and bsc#955811) we have setups
where the floating network was created with the wrong provider network
settings. While this somehow continued to work and got unnoticed it will
create problems on systems upgrading from juno to liberty. This fix tries to
to re-adjust the attributes directly neutron database to their correct values
to avoid problems during the upgrade.

https://bugzilla.suse.com/show_bug.cgi?id=967009
---
 .../crowbar-fix-floating-provider-attributes       | 61 ++++++++++++++++++++++
 .../files/default/crowbar-fix-router-port-binding  | 48 +++++++++++++++++
 .../cookbooks/neutron/recipes/post_install_conf.rb | 56 ++++++++++++++++++++
 3 files changed, 165 insertions(+)
 create mode 100644 chef/cookbooks/neutron/files/default/crowbar-fix-floating-provider-attributes
 create mode 100644 chef/cookbooks/neutron/files/default/crowbar-fix-router-port-binding

diff --git a/chef/cookbooks/neutron/files/default/crowbar-fix-floating-provider-attributes b/chef/cookbooks/neutron/files/default/crowbar-fix-floating-provider-attributes
new file mode 100644
index 0000000..e35ef4d
--- /dev/null
+++ b/chef/cookbooks/neutron/files/default/crowbar-fix-floating-provider-attributes
@@ -0,0 +1,61 @@
+#!/usr/bin/python
+import sqlalchemy
+import sys
+from oslo_config import cfg
+
+_cli_opts = [
+    cfg.StrOpt('network',
+               required=True,
+               help='name of the network to update'),
+    cfg.StrOpt('tenant_id',
+               required=True,
+               help='tenant_id of the network to update'),
+    cfg.StrOpt('type',
+               required=True,
+               help='new network type'),
+    cfg.StrOpt('segmentation_id',
+               required=True,
+               help='new segmentation_id'),
+    cfg.StrOpt('physnet',
+               required=True,
+               help='new physnet'),
+]
+
+_db_opts = [
+    cfg.StrOpt('connection',
+               deprecated_name='sql_connection',
+               default='',
+               secret=True,
+               help='URL to database'),
+]
+
+CONF = cfg.ConfigOpts()
+CONF.register_cli_opts(_db_opts, 'database')
+CONF.register_cli_opts(_cli_opts)
+CONF(project='neutron')
+
+db_uri = CONF.database.connection
+
+network = CONF.network
+tenant_id = CONF.tenant_id
+network_type = CONF.type
+segmentation_id = CONF.segmentation_id
+physnet = CONF.physnet
+
+db = sqlalchemy.create_engine(db_uri)
+try:
+    connection = db.connect()
+except sqlalchemy.exc.SQLAlchemyError as e:
+    print >>sys.stderr, 'Cannot connect to database: %s' % e
+    sys.exit(1)
+
+ret = connection.execute(
+    "UPDATE ml2_network_segments SET "
+    "network_type=%s, "
+    "segmentation_id=%s, "
+    "physical_network=%s "
+    "FROM networks WHERE "
+    "networks.name=%s AND "
+    "ml2_network_segments.network_id=networks.id AND "
+    "networks.tenant_id=%s;",
+    [network_type, segmentation_id, physnet, network, tenant_id])
diff --git a/chef/cookbooks/neutron/files/default/crowbar-fix-router-port-binding b/chef/cookbooks/neutron/files/default/crowbar-fix-router-port-binding
new file mode 100644
index 0000000..af06a65
--- /dev/null
+++ b/chef/cookbooks/neutron/files/default/crowbar-fix-router-port-binding
@@ -0,0 +1,48 @@
+#!/usr/bin/python
+
+import sqlalchemy
+import sys
+from oslo_config import cfg
+
+#from neutron import context
+#from neutron.common import utils
+#from neutron.db import api
+#from neutron.plugins.ml2 import db
+_cli_opts = [
+    cfg.StrOpt('router',
+               required=True,
+               help='name of the network to update'),
+]
+
+_db_opts = [
+    cfg.StrOpt('connection',
+               deprecated_name='sql_connection',
+               default='',
+               secret=True,
+               help='URL to database'),
+]
+
+CONF = cfg.ConfigOpts()
+CONF.register_cli_opts(_db_opts, 'database')
+CONF.register_cli_opts(_cli_opts)
+CONF(project='neutron')
+
+db_uri = CONF.database.connection
+
+router = CONF.router
+
+db = sqlalchemy.create_engine(db_uri)
+try:
+    connection = db.connect()
+except sqlalchemy.exc.SQLAlchemyError as e:
+    print >>sys.stderr, 'Cannot connect to database: %s' % e
+    sys.exit(1)
+
+ret = connection.execute(
+    "UPDATE ml2_port_bindings set vif_type='unbound' "
+    "FROM routers,ports "
+    "WHERE ml2_port_bindings.vif_type='binding_failed' "
+    "AND routers.name=%s "
+    "AND routers.id=ports.device_id "
+    "AND ports.device_owner='network:router_gateway' "
+    "AND ports.id=ml2_port_bindings.port_id;", router)
diff --git a/chef/cookbooks/neutron/recipes/post_install_conf.rb b/chef/cookbooks/neutron/recipes/post_install_conf.rb
index 1145721..48f5db8 100644
--- a/chef/cookbooks/neutron/recipes/post_install_conf.rb
+++ b/chef/cookbooks/neutron/recipes/post_install_conf.rb
@@ -92,6 +92,62 @@ def mask_to_bits(mask)
   else
     Chef::Log.error("default provider network ml2 type driver '#{ml2_type_drivers_default_provider_network}' invalid for creating provider networks")
   end
+
+  # *START* workaround for https://bugzilla.suse.com/show_bug.cgi?id=967009
+  unless node[:neutron][:floating_router_fix]
+    cookbook_file "crowbar-fix-floating-provider-attributes" do
+      source "crowbar-fix-floating-provider-attributes"
+      path "/usr/bin/crowbar-fix-floating-provider-attributes"
+      mode "0755"
+      only_if "out=$(#{neutron_cmd} net-show floating -f value -F provider:network_type); " \
+        "[ $? == 0 ] && [ ${out} != \"flat\" ]"
+    end
+
+    # This adjusts the provider attributes of the existing "floating" network
+    # to actually match what we want ("flat" network on the correct physnet)
+    execute "fix floating network provider attributes" do
+      command "/usr/bin/crowbar-fix-floating-provider-attributes " \
+        "--physnet #{ext_physnet_map["nova_floating"]} --segmentation_id 0 --type flat " \
+        "--tenant_id #{keystone_settings['service_tenant_id']} --network floating"
+      action :run
+      only_if "out=$(#{neutron_cmd} net-show floating -f value -F provider:network_type); " \
+        "[ $? == 0 ] && [ ${out} != \"flat\" ]"
+    end
+
+    if node[:neutron][:ml2_mechanism_drivers].include?("openvswitch")
+      # In case the router was created after https://bugzilla.suse.com/show_bug.cgi?id=946882
+      # was fixed, we likely had the wrong bridge mappings in the config and the
+      # gateway port is in a "binding_failed" state. This tries to reset the port.
+      cookbook_file "crowbar-fix-router-port-binding" do
+        source "crowbar-fix-router-port-binding"
+        path "/usr/bin/crowbar-fix-router-port-binding"
+        mode "0755"
+      end
+
+      execute "reset port binding for floating network (bsc#967009)" do
+        command "/usr/bin/crowbar-fix-router-port-binding --router router-floating"
+        action :run
+        only_if "out=$(#{neutron_cmd} router-list); [ $? != 0 ] || echo ${out} | grep -q router-floating"
+      end
+    end
+
+    ruby_block "mark node for having the floating network fixed (bsc#967009)" do
+      block do
+        node[:neutron][:floating_router_fix] = true
+        node.save
+      end
+    end
+  else
+    file "/usr/bin/crowbar-fix-floating-provider-attributes" do
+      action :delete
+    end
+
+    file "/usr/bin/crowbar-fix-router-port-binding" do
+      action :delete
+    end
+  end
+  # *END* workaround for https://bugzilla.suse.com/show_bug.cgi?id=967009
+
 when 'vmware'
   fixed_network_type = ""
   # We would like to be sure that floating network will be created
