components/openstack/keystone/files/keystone-upgrade
branchs11u2-sru
changeset 4380 2ac4d1fcad4a
parent 4217 631d20122b9c
child 4625 18adb92d4193
equal deleted inserted replaced
4361:17379d4babfa 4380:2ac4d1fcad4a
    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 KEYSTONE_CONF_MAPPINGS = {
    30 KEYSTONE_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'),
    79     ('ldap', 'tenant_additional_attribute_mapping'):
    76     ('ldap', 'tenant_additional_attribute_mapping'):
    80         ('ldap', 'project_additional_attribute_mapping'),
    77         ('ldap', 'project_additional_attribute_mapping'),
    81     ('DEFAULT', 'matchmaker_ringfile'): ('matchmaker_ring', 'ringfile'),
    78     ('DEFAULT', 'matchmaker_ringfile'): ('matchmaker_ring', 'ringfile'),
    82 }
    79 }
    83 
    80 
    84 
    81 KEYSTONE_CONF_EXCEPTIONS = [
    85 def update_mapping(section, key, mapping):
    82     ('DEFAULT', 'public_workers'),
    86     """ look for deprecated variables and, if found, convert it to the new
    83     ('DEFAULT', 'admin_workers'),
    87     section/key.
    84     ('database', 'connection'),
    88     """
    85 ]
    89 
       
    90     if (section, key) in mapping:
       
    91         print "Deprecated value found: [%s] %s" % (section, key)
       
    92         section, key = mapping[(section, key)]
       
    93         if section is None and key is None:
       
    94             print "Removing from configuration"
       
    95         else:
       
    96             print "Updating to: [%s] %s" % (section, key)
       
    97     return section, key
       
    98 
       
    99 
       
   100 def alter_mysql_tables(engine):
       
   101     """ Convert MySQL tables to use utf8
       
   102     """
       
   103 
       
   104     import MySQLdb
       
   105 
       
   106     for _none in range(5):
       
   107         try:
       
   108             db = MySQLdb.connect(host=engine.url.host,
       
   109                                  user=engine.url.username,
       
   110                                  passwd=engine.url.password,
       
   111                                  db=engine.url.database)
       
   112             break
       
   113         except MySQLdb.OperationalError as err:
       
   114             # mysql is not ready. sleep for 2 more seconds
       
   115             time.sleep(2)
       
   116     else:
       
   117         print "Unable to connect to MySQL:  %s" % err
       
   118         print ("Please verify MySQL is properly configured and online "
       
   119                "before using svcadm(1M) to clear this service.")
       
   120         sys.exit(smf_include.SMF_EXIT_ERR_FATAL)
       
   121 
       
   122     cursor = db.cursor()
       
   123     cursor.execute("ALTER DATABASE %s CHARACTER SET = 'utf8'" %
       
   124                    engine.url.database)
       
   125     cursor.execute("ALTER DATABASE %s COLLATE = 'utf8_general_ci'" %
       
   126                    engine.url.database)
       
   127     cursor.execute("SHOW tables")
       
   128     res = cursor.fetchall()
       
   129     if res:
       
   130         cursor.execute("SET foreign_key_checks = 0")
       
   131         for item in res:
       
   132             cursor.execute("ALTER TABLE %s.%s CONVERT TO "
       
   133                            "CHARACTER SET 'utf8', COLLATE 'utf8_general_ci'"
       
   134                            % (engine.url.database, item[0]))
       
   135         cursor.execute("SET foreign_key_checks = 1")
       
   136         db.commit()
       
   137         db.close()
       
   138 
       
   139 
       
   140 def modify_conf(old_file, mapping=None):
       
   141     """ Copy over all uncommented options from the old configuration file.  In
       
   142     addition, look for deprecated section/keys and convert them to the new
       
   143     section/key.
       
   144     """
       
   145 
       
   146     new_file = old_file + '.new'
       
   147 
       
   148     # open the previous version
       
   149     old = iniparse.ConfigParser()
       
   150     old.readfp(open(old_file))
       
   151 
       
   152     # open the new version
       
   153     new = iniparse.ConfigParser()
       
   154     try:
       
   155         new.readfp(open(new_file))
       
   156     except IOError as err:
       
   157         if err.errno == errno.ENOENT:
       
   158             # The upgrade did not deliver a .new file so, return
       
   159             print "%s not found - continuing with %s" % (new_file, old_file)
       
   160             return
       
   161         else:
       
   162             raise
       
   163     print "\nupdating %s" % old_file
       
   164 
       
   165     # walk every single section for uncommented options
       
   166     default_items = set(old.items('DEFAULT'))
       
   167     for section in old.sections() + ['DEFAULT']:
       
   168 
       
   169         # DEFAULT items show up in every section so remove them
       
   170         if section != 'DEFAULT':
       
   171             section_items = set(old.items(section)) - default_items
       
   172         else:
       
   173             section_items = default_items
       
   174 
       
   175         for key, value in section_items:
       
   176             # keep a copy of the old value
       
   177             oldvalue = value
       
   178             oldsection = section
       
   179 
       
   180             if mapping is not None:
       
   181                 section, key = update_mapping(section, key, mapping)
       
   182 
       
   183                 if section is None and key is None:
       
   184                     # option is deprecated so continue
       
   185                     continue
       
   186 
       
   187             if not new.has_section(section):
       
   188                 if section != 'DEFAULT':
       
   189                     new.add_section(section)
       
   190 
       
   191             # print to the log when a value for the same section.key is
       
   192             # changing to a new value
       
   193             try:
       
   194                 new_value = new.get(section, key)
       
   195                 if new_value != value and '%SERVICE' not in new_value:
       
   196                     print "Changing [%s] %s:\n- %s\n+ %s" % \
       
   197                         (section, key, oldvalue, new_value)
       
   198                     print
       
   199             except NoOptionError:
       
   200                 # the new configuration file does not have this option set so
       
   201                 # just continue
       
   202                 pass
       
   203 
       
   204             # Only copy the old value to the new conf file if the entry doesn't
       
   205             # exist or if it contains '%SERVICE'
       
   206             if not new.has_option(section, key) or \
       
   207                '%SERVICE' in new.get(section, key):
       
   208                 new.set(section, key, value)
       
   209             section = oldsection
       
   210 
       
   211     # copy the old conf file to a backup
       
   212     today = datetime.now().strftime("%Y%m%d%H%M%S")
       
   213     shutil.copy2(old_file, old_file + '.' + today)
       
   214 
       
   215     # copy the new conf file in place
       
   216     with open(old_file, 'wb+') as fh:
       
   217         new.write(fh)
       
   218 
    86 
   219 
    87 
   220 def start():
    88 def start():
   221     # pull out the current version of config/upgrade-id
    89     # pull out the current version of config/upgrade-id
   222     p = Popen(['/usr/bin/svcprop', '-p', 'config/upgrade-id',
    90     p = Popen(['/usr/bin/svcprop', '-p', 'config/upgrade-id',
   237 
   105 
   238     # look for any .new files
   106     # look for any .new files
   239     if glob.glob('/etc/keystone/*.new'):
   107     if glob.glob('/etc/keystone/*.new'):
   240         # the versions are different, so perform an upgrade
   108         # the versions are different, so perform an upgrade
   241         # modify the configuration files
   109         # modify the configuration files
   242         modify_conf('/etc/keystone/keystone.conf', KEYSTONE_CONF_MAPPINGS)
   110 
       
   111         # backup all the old configuration files
       
   112         create_backups('/etc/keystone')
       
   113 
       
   114         modify_conf('/etc/keystone/keystone.conf', KEYSTONE_CONF_MAPPINGS,
       
   115                     KEYSTONE_CONF_EXCEPTIONS)
   243         modify_conf('/etc/keystone/keystone-paste.ini')
   116         modify_conf('/etc/keystone/keystone-paste.ini')
   244         modify_conf('/etc/keystone/logging.conf')
   117         modify_conf('/etc/keystone/logging.conf')
   245 
   118 
   246     config = iniparse.RawConfigParser()
   119     config = iniparse.RawConfigParser()
   247     config.read('/etc/keystone/keystone.conf')
   120     config.read('/etc/keystone/keystone.conf')
   266 
   139 
   267 if __name__ == '__main__':
   140 if __name__ == '__main__':
   268     os.putenv('LC_ALL', 'C')
   141     os.putenv('LC_ALL', 'C')
   269     try:
   142     try:
   270         smf_include.smf_main()
   143         smf_include.smf_main()
       
   144     except RuntimeError:
       
   145         sys.exit(smf_include.SMF_EXIT_ERR_FATAL)
   271     except Exception as err:
   146     except Exception as err:
   272         print 'Unknown error:  %s' % err
   147         print 'Unknown error:  %s' % err
   273         print
   148         print
   274         traceback.print_exc(file=sys.stdout)
   149         traceback.print_exc(file=sys.stdout)
   275         sys.exit(smf_include.SMF_EXIT_ERR_FATAL)
   150         sys.exit(smf_include.SMF_EXIT_ERR_FATAL)