| #!/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. |
| |
| """ |
| |
| from ambari_commons.os_check import OSCheck |
| from resource_management.core.exceptions import ComponentIsNotRunning |
| from resource_management.core.exceptions import ExecutionFailed |
| from resource_management.core.logger import Logger |
| from resource_management.core.resources import User |
| from resource_management.core.resources.system import Directory |
| from resource_management.core.resources.system import Execute |
| from resource_management.core.resources.system import File |
| from resource_management.core.source import InlineTemplate |
| from resource_management.core.source import Template |
| from resource_management.libraries.functions.get_user_call_output import \ |
| get_user_call_output |
| |
| |
| def service_check(cmd, user, label): |
| """ |
| Executes a SysV service check command that adheres to LSB-compliant |
| return codes. The return codes are interpreted as defined |
| by the LSB. |
| |
| See http://refspecs.linuxbase.org/LSB_3.0.0/LSB-PDA/LSB-PDA/iniscrptact.html |
| for more information. |
| |
| :param cmd: The service check command to execute. |
| :param label: The name of the service. |
| """ |
| Logger.info("Performing service check; cmd={0}, user={1}, label={2}".format(cmd, user, label)) |
| rc, out, err = get_user_call_output(cmd, user, is_checked_call=False) |
| |
| if rc in [1, 2, 3]: |
| # if return code in [1, 2, 3], then 'program is not running' or 'program is dead' |
| Logger.info("{0} is not running".format(label)) |
| raise ComponentIsNotRunning() |
| |
| elif rc == 0: |
| # if return code = 0, then 'program is running or service is OK' |
| Logger.info("{0} is running".format(label)) |
| |
| else: |
| # else service state is unknown |
| err_msg = "{0} service check failed; cmd '{1}' returned {2}".format(label, cmd, rc) |
| Logger.error(err_msg) |
| raise ExecutionFailed(err_msg, rc, out, err) |
| |
| def is_systemd_running(): |
| """ |
| Determines if the platform is running Systemd. |
| :return True, if the platform is running Systemd. False, otherwise. |
| """ |
| Logger.info("Is the platform running Systemd?") |
| rc, out, err = get_user_call_output("pidof systemd", "root", is_checked_call=False) |
| if rc == 0: |
| Logger.info("Systemd was found") |
| return True |
| else: |
| Logger.info("Systemd was NOT found") |
| return False |
| |
| def configure_systemd(params): |
| """ |
| Configure Systemd for Elasticsearch. |
| """ |
| Logger.info("Configuring Systemd for Elasticsearch"); |
| |
| # ensure the systemd directory for elasticsearch overrides exists |
| Logger.info("Create Systemd directory for Elasticsearch: {0}".format(params.systemd_elasticsearch_dir)) |
| Directory(params.systemd_elasticsearch_dir, |
| create_parents=True, |
| owner='root', |
| group='root') |
| |
| # when using Elasticsearch packages on systems that use systemd, system |
| # limits must also be specified via systemd. |
| # see https://www.elastic.co/guide/en/elasticsearch/reference/5.6/setting-system-settings.html#systemd |
| Logger.info("Elasticsearch systemd limits: {0}".format(params.systemd_override_file)) |
| File(params.systemd_override_file, |
| content=InlineTemplate(params.systemd_override_template), |
| owner="root", |
| group="root") |
| |
| # reload the configuration |
| Execute("systemctl daemon-reload") |
| |
| def create_user(params): |
| """ |
| Creates the user required for Elasticsearch. |
| """ |
| Logger.info("Creating user={0} in group={1}".format(params.elastic_user, params.elastic_group)) |
| User(params.elastic_user, action = "create", groups = params.elastic_group) |
| |
| def create_directories(params, directories): |
| """ |
| Creates one or more directories. |
| """ |
| Logger.info("Creating directories: {0}".format(directories)) |
| Directory(directories, |
| create_parents=True, |
| mode=0755, |
| owner=params.elastic_user, |
| group=params.elastic_group |
| ) |
| |
| def create_elastic_env(params): |
| """ |
| Creates the Elasticsearch environment file. |
| """ |
| Logger.info("Create Elasticsearch environment file.") |
| File("{0}/elastic-env.sh".format(params.conf_dir), |
| owner=params.elastic_user, |
| group=params.elastic_group, |
| content=InlineTemplate(params.elastic_env_sh_template)) |
| |
| def create_elastic_site(params, template_name): |
| """ |
| Creates the Elasticsearch site file. |
| """ |
| Logger.info("Creating Elasticsearch site file; template={0}".format(template_name)) |
| |
| elastic_site = params.config['configurations']['elastic-site'] |
| path = "{0}/elasticsearch.yml".format(params.conf_dir) |
| template = Template(template_name, configurations=elastic_site) |
| File(path, |
| content=template, |
| owner=params.elastic_user, |
| group=params.elastic_group) |
| |
| def get_elastic_config_path(default="/etc/default/elasticsearch"): |
| """ |
| Defines the path to the Elasticsearch environment file. This path will |
| differ based on the OS family. |
| :param default: The path used if the OS family is not recognized. |
| """ |
| path = default |
| if OSCheck.is_redhat_family(): |
| path = "/etc/sysconfig/elasticsearch" |
| elif OSCheck.is_ubuntu_family(): |
| path = "/etc/default/elasticsearch" |
| else: |
| Logger.error("Unexpected OS family; using default path={0}".format(path)) |
| |
| return path |
| |
| def create_elastic_config(params): |
| """ |
| Creates the Elasticsearch system config file. Usually lands at either |
| /etc/sysconfig/elasticsearch or /etc/default/elasticsearch. |
| """ |
| path = get_elastic_config_path() |
| Logger.info("Creating the Elasticsearch system config; path={0}".format(path)) |
| File(path, owner="root", group="root", content=InlineTemplate(params.sysconfig_template)) |
| |
| def create_elastic_pam_limits(params): |
| """ |
| Creates the PAM limits for Elasticsearch. |
| """ |
| Logger.info("Creating Elasticsearch PAM limits.") |
| |
| # in some OS this folder may not exist, so create it |
| Logger.info("Ensure PAM limits directory exists: {0}".format(params.limits_conf_dir)) |
| Directory(params.limits_conf_dir, |
| create_parents=True, |
| owner='root', |
| group='root') |
| |
| Logger.info("Creating Elasticsearch PAM limits; file={0}".format(params.limits_conf_file)) |
| File(params.limits_conf_file, |
| content=Template('elasticsearch_limits.conf.j2'), |
| owner="root", |
| group="root") |
| |
| def create_elastic_jvm_options(params): |
| """ |
| Defines the jvm.options file used to specify JVM options. |
| """ |
| path = "{0}/jvm.options".format(params.conf_dir) |
| Logger.info("Creating Elasticsearch JVM Options; file={0}".format(path)) |
| File(path, |
| content=InlineTemplate(params.jvm_options_template), |
| owner=params.elastic_user, |
| group=params.elastic_group) |
| |
| def get_data_directories(params): |
| """ |
| Returns the directories to use for storing Elasticsearch data. |
| """ |
| path = params.path_data |
| path = path.replace('"', '') |
| path = path.replace(' ', '') |
| path = path.split(',') |
| dirs = [p.replace('"', '') for p in path] |
| |
| Logger.info("Elasticsearch data directories: dirs={0}".format(dirs)) |
| return dirs |
| |
| def configure_master(): |
| """ |
| Configures the Elasticsearch master node. |
| """ |
| import params |
| |
| # define the directories required |
| dirs = [ |
| params.log_dir, |
| params.pid_dir, |
| params.conf_dir, |
| "{0}/scripts".format(params.conf_dir) |
| ] |
| dirs += get_data_directories(params) |
| |
| # configure the elasticsearch master |
| create_user(params) |
| create_directories(params, dirs) |
| create_elastic_env(params) |
| create_elastic_site(params, "elasticsearch.master.yaml.j2") |
| create_elastic_config(params) |
| create_elastic_pam_limits(params) |
| create_elastic_jvm_options(params) |
| if is_systemd_running(): |
| configure_systemd(params) |
| |
| def configure_slave(): |
| """ |
| Configures the Elasticsearch slave node. |
| """ |
| import params |
| |
| # define the directories required |
| dirs = [ |
| params.log_dir, |
| params.pid_dir, |
| params.conf_dir, |
| ] |
| dirs += get_data_directories(params) |
| |
| # configure the elasticsearch slave |
| create_user(params) |
| create_directories(params, dirs) |
| create_elastic_env(params) |
| create_elastic_site(params, "elasticsearch.slave.yaml.j2") |
| create_elastic_config(params) |
| create_elastic_pam_limits(params) |
| create_elastic_jvm_options(params) |
| if is_systemd_running(): |
| configure_systemd(params) |