blob: d70e87fb1ed869c265360b14f08f67355abacf23 [file] [log] [blame]
#!/usr/bin/env python
"""
Licensed to the Apache Software Foundation (ASF) under one
or more contributor license agreements. See the NOTICE file
distributed with this work for additional information
regarding copyright ownership. The ASF licenses this file
to you 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.
Ambari Agent
"""
import os
import shutil
from ambari_commons.os_check import OSCheck
from resource_management.libraries.script import Script
from resource_management.libraries.functions import conf_select
from resource_management.libraries.functions import stack_tools
from resource_management.libraries.functions.constants import Direction
from resource_management.libraries.functions.default import default
from resource_management.libraries.functions.version import format_stack_version
from resource_management.core import shell
from resource_management.core.exceptions import Fail
from resource_management.core.logger import Logger
from resource_management.core.resources.system import Execute, Link, Directory
from resource_management.libraries.functions.stack_features import check_stack_feature
from resource_management.libraries.functions import StackFeature
class UpgradeSetAll(Script):
"""
This script is a part of Rolling Upgrade workflow and is used to set the
component versions as a final step in the upgrade process
"""
def actionexecute(self, env):
config = Script.get_config()
version = default('/commandParams/version', None)
stack_name = default('/hostLevelParams/stack_name', "")
if not version:
raise Fail("Value is required for '/commandParams/version'")
# other os?
if OSCheck.is_redhat_family():
cmd = ('/usr/bin/yum', 'clean', 'all')
code, out = shell.call(cmd, sudo=True)
real_ver = format_stack_version(version)
if real_ver and check_stack_feature(StackFeature.ROLLING_UPGRADE, real_ver):
stack_selector_path = stack_tools.get_stack_tool_path(stack_tools.STACK_SELECTOR_NAME)
cmd = ('ambari-python-wrap', stack_selector_path, 'set', 'all', version)
code, out = shell.call(cmd, sudo=True)
if real_ver and check_stack_feature(StackFeature.CONFIG_VERSIONING, real_ver):
# backup the old and symlink /etc/[component]/conf to <stack-root>/current/[component]
for k, v in conf_select.get_package_dirs().iteritems():
for dir_def in v:
link_config(dir_def['conf_dir'], dir_def['current_dir'])
def unlink_all_configs(self, env):
"""
Reverses the work performed in link_config. This should only be used when downgrading from
HDP 2.3 to 2.2 in order to under the symlink work required for 2.3.
"""
stack_name = default('/hostLevelParams/stack_name', "").upper()
downgrade_to_version = default('/commandParams/version', None)
downgrade_from_version = default('/commandParams/downgrade_from_version', None)
upgrade_direction = default("/commandParams/upgrade_direction", Direction.UPGRADE)
# downgrade only
if upgrade_direction != Direction.DOWNGRADE:
Logger.warning("Unlinking configurations should only be performed on a downgrade.")
return
if downgrade_to_version is None or downgrade_from_version is None:
Logger.warning("Both 'commandParams/version' and 'commandParams/downgrade_from_version' must be specified to unlink configs on downgrade.")
return
Logger.info("Unlinking all configs when downgrading from {0} {1} to {2}".format(
stack_name, downgrade_from_version, downgrade_to_version))
# normalize the versions
downgrade_to_version = format_stack_version(downgrade_to_version)
downgrade_from_version = format_stack_version(downgrade_from_version)
# downgrade-to-version must be 2.2 (less than 2.3)
if downgrade_to_version and check_stack_feature(StackFeature.CONFIG_VERSIONING, downgrade_to_version):
Logger.warning("Unlinking configurations should not be performed when downgrading {0} {1} to {2}".format(
stack_name, downgrade_from_version, downgrade_to_version))
return
# downgrade-from-version must be 2.3+
if not( downgrade_from_version and check_stack_feature(StackFeature.CONFIG_VERSIONING, downgrade_from_version) ):
Logger.warning("Unlinking configurations should not be performed when downgrading {0} {1} to {2}".format(
stack_name, downgrade_from_version, downgrade_to_version))
return
# iterate through all directory conf mappings and undo the symlinks
for key, value in conf_select.get_package_dirs().iteritems():
for directory_mapping in value:
original_config_directory = directory_mapping['conf_dir']
self._unlink_config(original_config_directory)
def _unlink_config(self, original_conf_directory):
"""
Reverses the work performed in link_config. This should only be used when downgrading from
HDP 2.3 to 2.2 in order to undo the conf symlink work required for 2.3.
1. Checks if conf.backup exists, if not then do no work
2. Check for existance of 'etc' symlink and remove it
3. Rename conf.back back to conf
:original_conf_directory: the original conf directory that was made into a symlink (/etc/component/conf)
"""
# calculate the parent and backup directories
original_conf_parent_directory = os.path.abspath(os.path.join(original_conf_directory, os.pardir))
backup_conf_directory = os.path.join(original_conf_parent_directory, "conf.backup")
Logger.info("Analyzing potential link {0}".format(original_conf_directory))
if os.path.islink(original_conf_directory):
# remove the old symlink
Execute(("rm", original_conf_directory), sudo=True)
elif os.path.isdir(original_conf_directory):
Directory(original_conf_directory, action="delete")
else:
Logger.info(" Skipping the unlink of {0}; it is not a symlink or does not exist".format(original_conf_directory))
if os.path.isdir(backup_conf_directory):
# rename the backup to the original name
Logger.info(" Unlinking {0} and restoring {1}".format(original_conf_directory, backup_conf_directory))
Execute(("mv", backup_conf_directory, original_conf_directory), sudo=True)
else:
Logger.info(" Skipping restoring config from backup {0} since it does not exist".format(backup_conf_directory))
def link_config(old_conf, link_conf):
"""
Creates a config link following:
1. Checks if the old_conf location exists
2. If it does, check if it's a link already
3. Make a copy to /etc/[component]/conf.backup
4. Remove the old directory and create a symlink to link_conf
:old_conf: the old config directory, ie /etc/[component]/conf
:link_conf: the new target for the config directory, ie <stack-root>/current/[component-dir]/conf
"""
if os.path.islink(old_conf):
# if the link exists but is wrong, then change it
if os.path.realpath(old_conf) != link_conf:
Link(old_conf, to = link_conf)
else:
Logger.debug("Skipping {0}; it is already a link".format(old_conf))
return
if not os.path.exists(old_conf):
Logger.debug("Skipping {0}; it does not exist".format(old_conf))
return
old_parent = os.path.abspath(os.path.join(old_conf, os.pardir))
Logger.info("Linking {0} to {1}".format(old_conf, link_conf))
old_conf_copy = os.path.join(old_parent, "conf.backup")
if not os.path.exists(old_conf_copy):
Execute(("cp", "-R", "-p", old_conf, old_conf_copy), sudo=True, logoutput=True)
shutil.rmtree(old_conf, ignore_errors=True)
# link /etc/[component]/conf -> <stack-root>/current/[component]-client/conf
Link(old_conf, to = link_conf)
if __name__ == "__main__":
UpgradeSetAll().execute()