components/openstack/heat/files/heat-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, \
       
    28     move_conf
    31 
    29 
    32 
    30 
    33 HEAT_CONF_MAPPINGS = {
    31 HEAT_CONF_MAPPINGS = {
    34     # Deprecated group/name
    32     # Deprecated group/name
    35     ('DEFAULT', 'stack_user_domain'): ('DEFAULT', 'stack_user_domain_id'),
    33     ('DEFAULT', 'stack_user_domain'): ('DEFAULT', 'stack_user_domain_id'),
    65     ('DEFAULT', 'instance_user'): (None, None),
    63     ('DEFAULT', 'instance_user'): (None, None),
    66     ('DEFAULT', 'onready'): (None, None),
    64     ('DEFAULT', 'onready'): (None, None),
    67     ('DEFAULT', 'list_notifier_drivers'): (None, None),
    65     ('DEFAULT', 'list_notifier_drivers'): (None, None),
    68 }
    66 }
    69 
    67 
       
    68 HEAT_CONF_EXCEPTIONS = [
       
    69     ('database', 'connection'),
       
    70     ('keystone_authtoken', 'auth_uri'),
       
    71     ('keystone_authtoken', 'identity_uri'),
       
    72     ('keystone_authtoken', 'admin_user'),
       
    73     ('keystone_authtoken', 'admin_password'),
       
    74     ('keystone_authtoken', 'admin_tenant_name'),
       
    75     ('keystone_authtoken', 'signing_dir'),
       
    76 ]
    70 
    77 
    71 def update_mapping(section, key, mapping):
    78 HEAT_MOVE_CONFIG = {
    72     """ look for deprecated variables and, if found, convert it to the new
    79     ('filter:authtoken', 'auth_uri'): ('keystone_authtoken', 'auth_uri'),
    73     section/key.
    80     ('filter:authtoken', 'identity_uri'):
    74     """
    81         ('keystone_authtoken', 'identity_uri'),
    75 
    82     ('filter:authtoken', 'admin_tenant_name'):
    76     if (section, key) in mapping:
    83         ('keystone_authtoken', 'admin_tenant_name'),
    77         print "Deprecated value found: [%s] %s" % (section, key)
    84     ('filter:authtoken', 'admin_user'): ('keystone_authtoken', 'admin_user'),
    78         section, key = mapping[(section, key)]
    85     ('filter:authtoken', 'admin_password'):
    79         if section is None and key is None:
    86         ('keystone_authtoken', 'admin_password'),
    80             print "Removing from configuration"
    87 }
    81         else:
       
    82             print "Updating to: [%s] %s" % (section, key)
       
    83     return section, key
       
    84 
       
    85 
       
    86 def alter_mysql_tables(engine):
       
    87     """ Convert MySQL tables to use utf8
       
    88     """
       
    89 
       
    90     import MySQLdb
       
    91 
       
    92     for _none in range(5):
       
    93         try:
       
    94             db = MySQLdb.connect(host=engine.url.host,
       
    95                                  user=engine.url.username,
       
    96                                  passwd=engine.url.password,
       
    97                                  db=engine.url.database)
       
    98             break
       
    99         except MySQLdb.OperationalError as err:
       
   100             # mysql is not ready. sleep for 2 more seconds
       
   101             time.sleep(2)
       
   102     else:
       
   103         print "Unable to connect to MySQL:  %s" % err
       
   104         print ("Please verify MySQL is properly configured and online "
       
   105                "before using svcadm(1M) to clear this service.")
       
   106         sys.exit(smf_include.SMF_EXIT_ERR_FATAL)
       
   107 
       
   108     cursor = db.cursor()
       
   109     cursor.execute("ALTER DATABASE %s CHARACTER SET = 'utf8'" %
       
   110                    engine.url.database)
       
   111     cursor.execute("ALTER DATABASE %s COLLATE = 'utf8_general_ci'" %
       
   112                    engine.url.database)
       
   113     cursor.execute("SHOW tables")
       
   114     res = cursor.fetchall()
       
   115     if res:
       
   116         cursor.execute("SET foreign_key_checks = 0")
       
   117         for item in res:
       
   118             cursor.execute("ALTER TABLE %s.%s CONVERT TO "
       
   119                            "CHARACTER SET 'utf8', COLLATE 'utf8_general_ci'"
       
   120                            % (engine.url.database, item[0]))
       
   121         cursor.execute("SET foreign_key_checks = 1")
       
   122         db.commit()
       
   123         db.close()
       
   124 
       
   125 
       
   126 def modify_conf(old_file, mapping=None):
       
   127     """ Copy over all uncommented options from the old configuration file.  In
       
   128     addition, look for deprecated section/keys and convert them to the new
       
   129     section/key.
       
   130     """
       
   131 
       
   132     new_file = old_file + '.new'
       
   133 
       
   134     # open the previous version
       
   135     old = iniparse.ConfigParser()
       
   136     old.readfp(open(old_file))
       
   137 
       
   138     # open the new version
       
   139     new = iniparse.ConfigParser()
       
   140     try:
       
   141         new.readfp(open(new_file))
       
   142     except IOError as err:
       
   143         if err.errno == errno.ENOENT:
       
   144             # The upgrade did not deliver a .new file so, return
       
   145             print "%s not found - continuing with %s" % (new_file, old_file)
       
   146             return
       
   147         else:
       
   148             raise
       
   149     print "\nupdating %s" % old_file
       
   150 
       
   151     # walk every single section for uncommented options
       
   152     default_items = set(old.items('DEFAULT'))
       
   153     for section in old.sections() + ['DEFAULT']:
       
   154 
       
   155         # DEFAULT items show up in every section so remove them
       
   156         if section != 'DEFAULT':
       
   157             section_items = set(old.items(section)) - default_items
       
   158         else:
       
   159             section_items = default_items
       
   160 
       
   161         for key, value in section_items:
       
   162             # keep a copy of the old value
       
   163             oldvalue = value
       
   164             oldsection = section
       
   165 
       
   166             if mapping is not None:
       
   167                 section, key = update_mapping(section, key, mapping)
       
   168 
       
   169                 if section is None and key is None:
       
   170                     # option is deprecated so continue
       
   171                     continue
       
   172 
       
   173             if not new.has_section(section):
       
   174                 if section != 'DEFAULT':
       
   175                     new.add_section(section)
       
   176 
       
   177             # print to the log when a value for the same section.key is
       
   178             # changing to a new value
       
   179             try:
       
   180                 new_value = new.get(section, key)
       
   181                 if new_value != value and '%SERVICE' not in new_value:
       
   182                     print "Changing [%s] %s:\n- %s\n+ %s" % \
       
   183                         (section, key, oldvalue, new_value)
       
   184                     print
       
   185             except NoOptionError:
       
   186                 # the new configuration file does not have this option set so
       
   187                 # just continue
       
   188                 pass
       
   189 
       
   190             # Only copy the old value to the new conf file if the entry doesn't
       
   191             # exist or if it contains '%SERVICE'
       
   192             if not new.has_option(section, key) or \
       
   193                '%SERVICE' in new.get(section, key):
       
   194                 new.set(section, key, value)
       
   195             section = oldsection
       
   196 
       
   197     # copy the old conf file to a backup
       
   198     today = datetime.now().strftime("%Y%m%d%H%M%S")
       
   199     shutil.copy2(old_file, old_file + '.' + today)
       
   200 
       
   201     # copy the new conf file in place
       
   202     with open(old_file, 'wb+') as fh:
       
   203         new.write(fh)
       
   204 
    88 
   205 
    89 
   206 def start():
    90 def start():
   207     # pull out the current version of config/upgrade-id
    91     # pull out the current version of config/upgrade-id
   208     p = Popen(['/usr/bin/svcprop', '-p', 'config/upgrade-id',
    92     p = Popen(['/usr/bin/svcprop', '-p', 'config/upgrade-id',
   223 
   107 
   224     # look for any .new files
   108     # look for any .new files
   225     if glob.glob('/etc/heat/*.new'):
   109     if glob.glob('/etc/heat/*.new'):
   226         # the versions are different, so perform an upgrade
   110         # the versions are different, so perform an upgrade
   227         # modify the configuration files
   111         # modify the configuration files
       
   112 
       
   113         # backup all the old configuration files
       
   114         create_backups('/etc/heat')
       
   115 
   228         modify_conf('/etc/heat/api-paste.ini')
   116         modify_conf('/etc/heat/api-paste.ini')
   229         modify_conf('/etc/heat/heat.conf', HEAT_CONF_MAPPINGS)
   117 
       
   118         # before modifying heat.conf, move the [filter:authtoken] entries from
       
   119         # the updated api-paste.ini to the old heat.conf
       
   120         move_conf('/etc/heat/api-paste.ini', '/etc/heat/heat.conf',
       
   121                   HEAT_MOVE_CONFIG)
       
   122 
       
   123         modify_conf('/etc/heat/heat.conf', HEAT_CONF_MAPPINGS,
       
   124                     HEAT_CONF_EXCEPTIONS)
   230 
   125 
   231     config = iniparse.RawConfigParser()
   126     config = iniparse.RawConfigParser()
   232     config.read('/etc/heat/heat.conf')
   127     config.read('/etc/heat/heat.conf')
   233     # In certain cases the database section does not exist and the
   128     # In certain cases the database section does not exist and the
   234     # default database chosen is sqlite.
   129     # default database chosen is sqlite.
   251 
   146 
   252 if __name__ == '__main__':
   147 if __name__ == '__main__':
   253     os.putenv('LC_ALL', 'C')
   148     os.putenv('LC_ALL', 'C')
   254     try:
   149     try:
   255         smf_include.smf_main()
   150         smf_include.smf_main()
       
   151     except RuntimeError:
       
   152         sys.exit(smf_include.SMF_EXIT_ERR_FATAL)
   256     except Exception as err:
   153     except Exception as err:
   257         print 'Unknown error:  %s' % err
   154         print 'Unknown error:  %s' % err
   258         print
   155         print
   259         traceback.print_exc(file=sys.stdout)
   156         traceback.print_exc(file=sys.stdout)
   260         sys.exit(smf_include.SMF_EXIT_ERR_FATAL)
   157         sys.exit(smf_include.SMF_EXIT_ERR_FATAL)