# Copyright (c) 2013 Hortonworks, Inc. # # Licensed 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. import re from oslo_log import log as logging from sahara.i18n import _ from sahara.i18n import _LI from sahara.plugins import exceptions as ex from sahara.plugins.hdp import saharautils from sahara.utils import cluster_progress_ops as cpo from sahara.utils import files as f AMBARI_RPM = ('http://s3.amazonaws.com/public-repo-1.hortonworks.com/' 'ambari/centos6/1.x/updates/1.6.0/ambari.repo') EPEL_RELEASE_PACKAGE_NAME = 'epel-release' HADOOP_SWIFT_RPM = ('https://s3.amazonaws.com/public-repo-1.hortonworks.com/' 'sahara/swift/hadoop-swift-1.0-1.x86_64.rpm') HADOOP_SWIFT_LOCAL_RPM = ('/opt/hdp-local-repos/hadoop-swift/' 'hadoop-swift-1.0-1.x86_64.rpm') LOG = logging.getLogger(__name__) class HadoopServer(object): _master_ip = None def __init__(self, instance, node_group, ambari_rpm=None): self.instance = instance self.node_group = node_group self.ambari_rpm = ambari_rpm or AMBARI_RPM def get_event_info(self): return self.instance @property def cluster_id(self): return self.instance.cluster_id @cpo.event_wrapper(True, param=('self', 0)) def provision_ambari(self, ambari_info, cluster_spec): self.install_rpms() global_config = cluster_spec.configurations['global'] jdk_path = global_config.get('java64_home') if 'AMBARI_SERVER' in self.node_group.components: self._setup_and_start_ambari_server(ambari_info.port, jdk_path) # all nodes must run Ambari agent self._setup_and_start_ambari_agent(ambari_info.host.internal_ip) @saharautils.inject_remote('r') def rpms_installed(self, r): rpm_cmd = 'rpm -q %s' % EPEL_RELEASE_PACKAGE_NAME ret_code, stdout = r.execute_command(rpm_cmd, run_as_root=True, raise_when_error=False) return ret_code == 0 @saharautils.inject_remote('r') def install_rpms(self, r): LOG.debug("Installing rpm's") # TODO(jspeidel): based on image type, use correct command curl_cmd = ('curl -f -s -o /etc/yum.repos.d/ambari.repo %s' % self.ambari_rpm) ret_code, stdout = r.execute_command(curl_cmd, run_as_root=True, raise_when_error=False) if ret_code == 0: yum_cmd = 'yum -y install %s' % EPEL_RELEASE_PACKAGE_NAME r.execute_command(yum_cmd, run_as_root=True) else: LOG.debug("Unable to install rpm's from repo, " "checking for local install.") if not self.rpms_installed(): raise ex.HadoopProvisionError( _('Failed to install Hortonworks Ambari')) @cpo.event_wrapper(True, param=('self', 0)) @saharautils.inject_remote('r') def install_swift_integration(self, r): LOG.debug("Installing swift integration") base_rpm_cmd = 'rpm -U --quiet ' rpm_cmd = base_rpm_cmd + HADOOP_SWIFT_RPM ret_code, stdout = r.execute_command(rpm_cmd, run_as_root=True, raise_when_error=False) if ret_code != 0: LOG.debug("Unable to install swift integration from " "source, checking for local rpm.") ret_code, stdout = r.execute_command( 'ls ' + HADOOP_SWIFT_LOCAL_RPM, run_as_root=True, raise_when_error=False) if ret_code == 0: rpm_cmd = base_rpm_cmd + HADOOP_SWIFT_LOCAL_RPM r.execute_command(rpm_cmd, run_as_root=True) else: raise ex.HadoopProvisionError( _('Failed to install Hadoop Swift integration')) @cpo.event_wrapper(True, param=('self', 0)) @saharautils.inject_remote('r') def configure_topology(self, topology_str, r): r.write_file_to( '/etc/hadoop/conf/topology.sh', f.get_file_text( 'plugins/hdp/versions/version_2_0_6/resources/topology.sh')) r.execute_command( 'chmod +x /etc/hadoop/conf/topology.sh', run_as_root=True ) r.write_file_to('/etc/hadoop/conf/topology.data', topology_str) @saharautils.inject_remote('r') def _setup_and_start_ambari_server(self, port, jdk_path, r): LOG.debug('Installing ambari-server') r.execute_command('yum -y install ambari-server', run_as_root=True) LOG.debug('Running Ambari Server setup') # remove postgres data directory as a precaution since its existence # has prevented successful postgres installation r.execute_command('rm -rf /var/lib/pgsql/data', run_as_root=True) # determine if the JDK is installed on this image # in the case of the plain image, no JDK will be available return_code, stdout = r.execute_command('ls -l {jdk_location}'.format( jdk_location=jdk_path), raise_when_error=False) LOG.debug('Queried for JDK location on VM instance, return code = ' '{code}'.format(code=str(return_code))) # do silent setup since we only use default responses now # only add -j command if the JDK is configured for the template, # and if the JDK is present # in all other cases, allow Ambari to install the JDK r.execute_command( 'ambari-server setup -s {jdk_arg} > /dev/null 2>&1'.format( jdk_arg='-j ' + jdk_path if jdk_path and (return_code == 0) else ''), run_as_root=True, timeout=1800 ) self._configure_ambari_server_api_port(port) # NOTE(dmitryme): Reading stdout from 'ambari-server start' # hangs ssh. Redirecting output to /dev/null fixes that r.execute_command( 'ambari-server start > /dev/null 2>&1', run_as_root=True ) LOG.info(_LI('Ambari started')) @saharautils.inject_remote('r') def _configure_ambari_server_api_port(self, port, r): # do nothing if port is not specified or is default if port is None or port == 8080: return ambari_config_file = '/etc/ambari-server/conf/ambari.properties' LOG.debug('Configuring Ambari Server API port: {port}'.format( port=port)) # read the current contents data = r.read_file_from(ambari_config_file) data = '{0}\nclient.api.port={1}\n'.format(data, port) # write the file back r.write_file_to(ambari_config_file, data, run_as_root=True) @saharautils.inject_remote('r') def _setup_and_start_ambari_agent(self, ambari_server_ip, r): LOG.debug('Installing Ambari agent') r.execute_command('yum -y install ambari-agent', run_as_root=True) LOG.debug( 'Setting master-ip: {ip} in ambari-agent.ini'.format( ip=ambari_server_ip)) r.replace_remote_string( '/etc/ambari-agent/conf/ambari-agent.ini', 'localhost', ambari_server_ip) # If the HDP 2 ambari agent is pre-installed on an image, the agent # will start up during instance launch and therefore the agent # registration will fail. It is therefore more appropriate to call # restart since it will either start (if stopped) or restart (if # running) r.execute_command('ambari-agent restart', run_as_root=True) LOG.info(_LI('Ambari Agent started')) @saharautils.inject_remote('r') def set_namenode_safemode(self, jh, r): r.execute_command("sudo su -l hdfs -c 'JAVA_HOME={0} " "hdfs dfsadmin -safemode enter'".format(jh), run_as_root=True) @saharautils.inject_remote('r') def save_namenode_namespace(self, jh, r): r.execute_command("sudo su -l hdfs -c 'JAVA_HOME={0} " "hdfs dfsadmin -saveNamespace'".format(jh), run_as_root=True) @saharautils.inject_remote('r') def initialize_shared_edits(self, jh, r): r.execute_command("sudo su -l hdfs -c 'JAVA_HOME={0} " "hdfs namenode -initializeSharedEdits'".format(jh), run_as_root=True) @saharautils.inject_remote('r') def format_zookeeper_fc(self, jh, r): r.execute_command("sudo su -l hdfs -c 'JAVA_HOME={0} " "hdfs zkfc -formatZK'".format(jh), run_as_root=True) @saharautils.inject_remote('r') def bootstrap_standby_namenode(self, jh, r): r.execute_command("sudo su -l hdfs -c 'JAVA_HOME={0} " "hdfs namenode -bootstrapStandby'".format(jh), run_as_root=True) @saharautils.inject_remote('r') def install_httpfs(self, r): r.execute_command("yum -y install hadoop-httpfs", run_as_root=True) @saharautils.inject_remote('r') def start_httpfs(self, r): r.execute_command("service hadoop-httpfs start", run_as_root=True) @saharautils.inject_remote('r') def write_hue_temp_file(self, filename, content, r): r.execute_command("echo %s > %s" % (content, filename), run_as_root=True) def _log(self, buf): # FIXME(Kezar): I don't know what's this. Will check later. LOG.debug(buf) def _is_component_available(self, component): return component in self.node_group.components def _is_ganglia_master(self): return self._is_component_available('GANGLIA_SERVER') def _is_ganglia_slave(self): return self._is_component_available('GANGLIA_MONITOR') class DefaultPromptMatcher(object): prompt_pattern = re.compile('(.*\()(.)(\)\?\s*$)', re.DOTALL) def __init__(self, terminal_token): self.eof_token = terminal_token def get_response(self, s): match = self.prompt_pattern.match(s) if match: response = match.group(2) return response else: return None def is_eof(self, s): eof = self.eof_token in s return eof