components/openstack/neutron/files/neutron-upgrade
branchs11-update
changeset 4314 96c1b7e2e45c
parent 4207 787ed839f409
child 4625 18adb92d4193
child 4704 fee46b752e18
equal deleted inserted replaced
4313:ab47f4c0c6fc 4314:96c1b7e2e45c
    12 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    12 #    distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
    13 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    13 #    WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
    14 #    License for the specific language governing permissions and limitations
    14 #    License for the specific language governing permissions and limitations
    15 #    under the License.
    15 #    under the License.
    16 
    16 
    17 from ConfigParser import NoOptionError
       
    18 from datetime import datetime
       
    19 import errno
       
    20 import glob
    17 import glob
    21 import os
    18 import os
    22 import shutil
       
    23 from subprocess import check_call, Popen, PIPE
    19 from subprocess import check_call, Popen, PIPE
    24 import sys
    20 import sys
    25 import time
       
    26 import traceback
    21 import traceback
    27 
    22 
    28 import iniparse
    23 import iniparse
    29 import smf_include
    24 import smf_include
    30 import sqlalchemy
    25 import sqlalchemy
       
    26 
       
    27 from openstack_common import alter_mysql_tables, create_backups, modify_conf
    31 
    28 
    32 
    29 
    33 NEUTRON_CONF_MAPPINGS = {
    30 NEUTRON_CONF_MAPPINGS = {
    34     # Deprecated group/name
    31     # Deprecated group/name
    35     ('DEFAULT', 'rabbit_durable_queues'): ('DEFAULT', 'amqp_durable_queues'),
    32     ('DEFAULT', 'rabbit_durable_queues'): ('DEFAULT', 'amqp_durable_queues'),
    36     ('rpc_notifier2', 'topics'): ('DEFAULT', 'notification_topics'),
    33     ('rpc_notifier2', 'topics'): ('DEFAULT', 'notification_topics'),
    37     ('DEFAULT', 'matchmaker_ringfile'): ('matchmaker_ring', 'ringfile'),
    34     ('DEFAULT', 'matchmaker_ringfile'): ('matchmaker_ring', 'ringfile'),
    38     # As of Juno, EVS now uses the standard quota driver
    35     # As of Juno, EVS now uses the standard quota driver
    39     ('quotas', 'quota_driver'): (None, None)
    36     ('quotas', 'quota_driver'): (None, None),
    40 }
    37 }
       
    38 
       
    39 NEUTRON_CONF_EXCEPTIONS = [
       
    40     ('DEFAULT', 'lockpath'),
       
    41     ('keystone_authtoken', 'auth_uri'),
       
    42     ('keystone_authtoken', 'identity_uri'),
       
    43     ('keystone_authtoken', 'admin_tenant_name'),
       
    44     ('keystone_authtoken', 'admin_user'),
       
    45     ('keystone_authtoken', 'admin_password'),
       
    46     ('keystone_authtoken', 'signing_dir'),
       
    47     ('database', 'connection'),
       
    48 ]
       
    49 
    41 
    50 
    42 DHCP_AGENT_MAPPINGS = {
    51 DHCP_AGENT_MAPPINGS = {
    43     # Deprecated group/name
    52     # Deprecated group/name
    44     ('DEFAULT', 'dnsmasq_dns_server'): ('DEFAULT', 'dnsmasq_dns_servers'),
    53     ('DEFAULT', 'dnsmasq_dns_server'): ('DEFAULT', 'dnsmasq_dns_servers'),
    45 }
    54 }
    47 EVS_PLUGIN_MAPPINGS = {
    56 EVS_PLUGIN_MAPPINGS = {
    48     # No longer referenced by the service
    57     # No longer referenced by the service
    49     ('DATABASE', 'sql_connection'): (None, None),
    58     ('DATABASE', 'sql_connection'): (None, None),
    50 }
    59 }
    51 
    60 
       
    61 L3_AGENT_EXCEPTIONS = [
       
    62     ('DEFAULT', 'enable_metadata_proxy'),
       
    63 ]
    52 
    64 
    53 def update_mapping(section, key, mapping):
    65 METADATA_AGENT_EXCEPTIONS = [
    54     """ look for deprecated variables and, if found, convert it to the new
    66     ('DEFAULT', 'auth_url'),
    55     section/key.
    67     ('DEFAULT', 'auth_region'),
    56     """
    68     ('DEFAULT', 'admin_tenant_name'),
    57 
    69     ('DEFAULT', 'admin_user'),
    58     if (section, key) in mapping:
    70     ('DEFAULT', 'admin_password'),
    59         print "Deprecated value found: [%s] %s" % (section, key)
    71     ('DEFAULT', 'metadata_workers'),
    60         section, key = mapping[(section, key)]
    72 ]
    61         if section is None and key is None:
       
    62             print "Removing from configuration"
       
    63         else:
       
    64             print "Updating to: [%s] %s" % (section, key)
       
    65     return section, key
       
    66 
       
    67 
       
    68 def alter_mysql_tables(engine):
       
    69     """ Convert MySQL tables to use utf8
       
    70     """
       
    71 
       
    72     import MySQLdb
       
    73 
       
    74     for _none in range(5):
       
    75         try:
       
    76             db = MySQLdb.connect(host=engine.url.host,
       
    77                                  user=engine.url.username,
       
    78                                  passwd=engine.url.password,
       
    79                                  db=engine.url.database)
       
    80             break
       
    81         except MySQLdb.OperationalError as err:
       
    82             # mysql is not ready. sleep for 2 more seconds
       
    83             time.sleep(2)
       
    84     else:
       
    85         print "Unable to connect to MySQL:  %s" % err
       
    86         print ("Please verify MySQL is properly configured and online "
       
    87                "before using svcadm(1M) to clear this service.")
       
    88         sys.exit(smf_include.SMF_EXIT_ERR_FATAL)
       
    89 
       
    90     cursor = db.cursor()
       
    91     cursor.execute("ALTER DATABASE %s CHARACTER SET = 'utf8'" %
       
    92                    engine.url.database)
       
    93     cursor.execute("ALTER DATABASE %s COLLATE = 'utf8_general_ci'" %
       
    94                    engine.url.database)
       
    95     cursor.execute("SHOW tables")
       
    96     res = cursor.fetchall()
       
    97     if res:
       
    98         cursor.execute("SET foreign_key_checks = 0")
       
    99         for item in res:
       
   100             cursor.execute("ALTER TABLE %s.%s CONVERT TO "
       
   101                            "CHARACTER SET 'utf8', COLLATE 'utf8_general_ci'"
       
   102                            % (engine.url.database, item[0]))
       
   103         cursor.execute("SET foreign_key_checks = 1")
       
   104         db.commit()
       
   105         db.close()
       
   106 
       
   107 
       
   108 def modify_conf(old_file, mapping=None):
       
   109     """ Copy over all uncommented options from the old configuration file.  In
       
   110     addition, look for deprecated section/keys and convert them to the new
       
   111     section/key.
       
   112     """
       
   113 
       
   114     new_file = old_file + '.new'
       
   115 
       
   116     # open the previous version
       
   117     old = iniparse.ConfigParser()
       
   118     old.readfp(open(old_file))
       
   119 
       
   120     # open the new version
       
   121     new = iniparse.ConfigParser()
       
   122     try:
       
   123         new.readfp(open(new_file))
       
   124     except IOError as err:
       
   125         if err.errno == errno.ENOENT:
       
   126             # The upgrade did not deliver a .new file so, return
       
   127             print "%s not found - continuing with %s" % (new_file, old_file)
       
   128             return
       
   129         else:
       
   130             raise
       
   131     print "\nupdating %s" % old_file
       
   132 
       
   133     # walk every single section for uncommented options
       
   134     default_items = set(old.items('DEFAULT'))
       
   135     for section in old.sections() + ['DEFAULT']:
       
   136 
       
   137         # DEFAULT items show up in every section so remove them
       
   138         if section != 'DEFAULT':
       
   139             section_items = set(old.items(section)) - default_items
       
   140         else:
       
   141             section_items = default_items
       
   142 
       
   143         for key, value in section_items:
       
   144             # keep a copy of the old value
       
   145             oldvalue = value
       
   146             oldsection = section
       
   147 
       
   148             if mapping is not None:
       
   149                 section, key = update_mapping(section, key, mapping)
       
   150 
       
   151                 if section is None and key is None:
       
   152                     # option is deprecated so continue
       
   153                     continue
       
   154 
       
   155             if not new.has_section(section):
       
   156                 if section != 'DEFAULT':
       
   157                     new.add_section(section)
       
   158 
       
   159             # print to the log when a value for the same section.key is
       
   160             # changing to a new value
       
   161             try:
       
   162                 new_value = new.get(section, key)
       
   163                 if new_value != value and '%SERVICE' not in new_value:
       
   164                     print "Changing [%s] %s:\n- %s\n+ %s" % \
       
   165                         (section, key, oldvalue, new_value)
       
   166                     print
       
   167             except NoOptionError:
       
   168                 # the new configuration file does not have this option set so
       
   169                 # just continue
       
   170                 pass
       
   171 
       
   172             # Only copy the old value to the new conf file if the entry doesn't
       
   173             # exist or if it contains '%SERVICE'
       
   174             if not new.has_option(section, key) or \
       
   175                '%SERVICE' in new.get(section, key):
       
   176                 new.set(section, key, value)
       
   177             section = oldsection
       
   178 
       
   179     # copy the old conf file to a backup
       
   180     today = datetime.now().strftime("%Y%m%d%H%M%S")
       
   181     shutil.copy2(old_file, old_file + '.' + today)
       
   182 
       
   183     # copy the new conf file in place
       
   184     with open(old_file, 'wb+') as fh:
       
   185         new.write(fh)
       
   186 
    73 
   187 
    74 
   188 def start():
    75 def start():
   189     # pull out the current version of config/upgrade-id
    76     # pull out the current version of config/upgrade-id
   190     p = Popen(['/usr/bin/svcprop', '-p', 'config/upgrade-id',
    77     p = Popen(['/usr/bin/svcprop', '-p', 'config/upgrade-id',
   205 
    92 
   206     # look for any .new files
    93     # look for any .new files
   207     if glob.glob('/etc/neutron/*.new'):
    94     if glob.glob('/etc/neutron/*.new'):
   208         # the versions are different, so perform an upgrade
    95         # the versions are different, so perform an upgrade
   209         # modify the configuration files
    96         # modify the configuration files
       
    97 
       
    98         # backup all the old configuration files
       
    99         create_backups('/etc/neutron')
       
   100 
   210         modify_conf('/etc/neutron/api-paste.ini')
   101         modify_conf('/etc/neutron/api-paste.ini')
   211         modify_conf('/etc/neutron/dhcp_agent.ini', DHCP_AGENT_MAPPINGS)
   102         modify_conf('/etc/neutron/dhcp_agent.ini', DHCP_AGENT_MAPPINGS)
   212         modify_conf('/etc/neutron/l3_agent.ini')
   103         modify_conf('/etc/neutron/l3_agent.ini', None, L3_AGENT_EXCEPTIONS)
   213         modify_conf('/etc/neutron/neutron.conf', NEUTRON_CONF_MAPPINGS)
   104         modify_conf('/etc/neutron/neutron.conf', NEUTRON_CONF_MAPPINGS,
       
   105                     NEUTRON_CONF_EXCEPTIONS)
   214         modify_conf('/etc/neutron/plugins/evs/evs_plugin.ini',
   106         modify_conf('/etc/neutron/plugins/evs/evs_plugin.ini',
   215                     EVS_PLUGIN_MAPPINGS)
   107                     EVS_PLUGIN_MAPPINGS)
       
   108         modify_conf('/etc/neutron/metadata_agent.ini', None,
       
   109                     METADATA_AGENT_EXCEPTIONS)
   216 
   110 
   217     config = iniparse.RawConfigParser()
   111     config = iniparse.RawConfigParser()
   218     config.read('/etc/neutron/neutron.conf')
   112     config.read('/etc/neutron/neutron.conf')
   219     # In certain cases the database section does not exist and the
   113     # In certain cases the database section does not exist and the
   220     # default database chosen is sqlite.
   114     # default database chosen is sqlite.
   246 
   140 
   247 if __name__ == '__main__':
   141 if __name__ == '__main__':
   248     os.putenv('LC_ALL', 'C')
   142     os.putenv('LC_ALL', 'C')
   249     try:
   143     try:
   250         smf_include.smf_main()
   144         smf_include.smf_main()
       
   145     except RuntimeError:
       
   146         sys.exit(smf_include.SMF_EXIT_ERR_FATAL)
   251     except Exception as err:
   147     except Exception as err:
   252         print 'Unknown error:  %s' % err
   148         print 'Unknown error:  %s' % err
   253         print
   149         print
   254         traceback.print_exc(file=sys.stdout)
   150         traceback.print_exc(file=sys.stdout)
   255         sys.exit(smf_include.SMF_EXIT_ERR_FATAL)
   151         sys.exit(smf_include.SMF_EXIT_ERR_FATAL)