blob: d0f8aa833df4c49701c718bb84265d7cc78ff336 [file] [log] [blame]
/*
* 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.
*/
package org.apache.ambari.server.upgrade;
import javax.persistence.EntityManager;
import javax.persistence.Query;
import javax.persistence.TypedQuery;
import java.io.File;
import java.io.FileReader;
import java.lang.reflect.Type;
import java.sql.Clob;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.atomic.AtomicLong;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.agent.RecoveryConfigHelper;
import org.apache.ambari.server.api.services.AmbariMetaInfo;
import org.apache.ambari.server.configuration.Configuration;
import org.apache.ambari.server.controller.AmbariManagementController;
import org.apache.ambari.server.orm.DBAccessor.DBColumnInfo;
import org.apache.ambari.server.orm.dao.AlertDefinitionDAO;
import org.apache.ambari.server.orm.dao.ArtifactDAO;
import org.apache.ambari.server.orm.dao.ClusterDAO;
import org.apache.ambari.server.orm.dao.PermissionDAO;
import org.apache.ambari.server.orm.dao.PrincipalDAO;
import org.apache.ambari.server.orm.dao.PrincipalTypeDAO;
import org.apache.ambari.server.orm.dao.PrivilegeDAO;
import org.apache.ambari.server.orm.dao.RemoteAmbariClusterDAO;
import org.apache.ambari.server.orm.dao.RequestScheduleDAO;
import org.apache.ambari.server.orm.dao.ResourceTypeDAO;
import org.apache.ambari.server.orm.dao.RoleAuthorizationDAO;
import org.apache.ambari.server.orm.dao.UserDAO;
import org.apache.ambari.server.orm.dao.ViewInstanceDAO;
import org.apache.ambari.server.orm.dao.WidgetDAO;
import org.apache.ambari.server.orm.entities.AlertDefinitionEntity;
import org.apache.ambari.server.orm.entities.ArtifactEntity;
import org.apache.ambari.server.orm.entities.ClusterEntity;
import org.apache.ambari.server.orm.entities.PermissionEntity;
import org.apache.ambari.server.orm.entities.PrincipalEntity;
import org.apache.ambari.server.orm.entities.PrincipalTypeEntity;
import org.apache.ambari.server.orm.entities.PrivilegeEntity;
import org.apache.ambari.server.orm.entities.RemoteAmbariClusterEntity;
import org.apache.ambari.server.orm.entities.RequestScheduleEntity;
import org.apache.ambari.server.orm.entities.ResourceEntity;
import org.apache.ambari.server.orm.entities.ResourceTypeEntity;
import org.apache.ambari.server.orm.entities.RoleAuthorizationEntity;
import org.apache.ambari.server.orm.entities.UserEntity;
import org.apache.ambari.server.orm.entities.ViewEntityEntity;
import org.apache.ambari.server.orm.entities.ViewInstanceEntity;
import org.apache.ambari.server.orm.entities.WidgetEntity;
import org.apache.ambari.server.security.authorization.ResourceType;
import org.apache.ambari.server.security.authorization.User;
import org.apache.ambari.server.security.authorization.Users;
import org.apache.ambari.server.state.AlertFirmness;
import org.apache.ambari.server.state.Cluster;
import org.apache.ambari.server.state.Clusters;
import org.apache.ambari.server.state.Config;
import org.apache.ambari.server.state.ConfigHelper;
import org.apache.ambari.server.state.RepositoryType;
import org.apache.ambari.server.state.SecurityType;
import org.apache.ambari.server.state.ServiceInfo;
import org.apache.ambari.server.state.StackId;
import org.apache.ambari.server.state.StackInfo;
import org.apache.ambari.server.state.State;
import org.apache.ambari.server.state.kerberos.KerberosComponentDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosDescriptorFactory;
import org.apache.ambari.server.state.kerberos.KerberosIdentityDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosKeytabDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosPrincipalDescriptor;
import org.apache.ambari.server.state.kerberos.KerberosServiceDescriptor;
import org.apache.ambari.server.state.stack.WidgetLayout;
import org.apache.ambari.server.state.stack.WidgetLayoutInfo;
import org.apache.ambari.server.view.DefaultMasker;
import org.apache.ambari.view.ClusterType;
import org.apache.ambari.view.MaskException;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.jdbc.support.JdbcUtils;
import com.google.common.collect.Lists;
import com.google.common.reflect.TypeToken;
import com.google.gson.Gson;
import com.google.gson.JsonArray;
import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.google.gson.JsonPrimitive;
import com.google.inject.Inject;
import com.google.inject.Injector;
import com.google.inject.persist.Transactional;
/**
* Upgrade catalog for version 2.4.0.
*/
public class UpgradeCatalog240 extends AbstractUpgradeCatalog {
protected static final String ADMIN_PERMISSION_TABLE = "adminpermission";
protected static final String PRINCIPAL_ID_COL = "principal_id";
protected static final String ALERT_DEFINITION_TABLE = "alert_definition";
protected static final String ALERT_TARGET_TABLE = "alert_target";
protected static final String ALERT_TARGET_ENABLED_COLUMN = "is_enabled";
protected static final String ALERT_CURRENT_TABLE = "alert_current";
protected static final String ALERT_CURRENT_OCCURRENCES_COLUMN = "occurrences";
protected static final String ALERT_CURRENT_FIRMNESS_COLUMN = "firmness";
protected static final String HELP_URL_COLUMN = "help_url";
protected static final String REPEAT_TOLERANCE_COLUMN = "repeat_tolerance";
protected static final String REPEAT_TOLERANCE_ENABLED_COLUMN = "repeat_tolerance_enabled";
protected static final String PERMISSION_ID_COL = "permission_name";
protected static final String SORT_ORDER_COL = "sort_order";
protected static final String REPO_VERSION_TABLE = "repo_version";
protected static final String HOST_ROLE_COMMAND_TABLE = "host_role_command";
protected static final String SERVICE_COMPONENT_DS_TABLE = "servicecomponentdesiredstate";
protected static final String HOST_COMPONENT_DS_TABLE = "hostcomponentdesiredstate";
protected static final String HOST_COMPONENT_STATE_TABLE = "hostcomponentstate";
protected static final String SERVICE_COMPONENT_HISTORY_TABLE = "servicecomponent_history";
protected static final String UPGRADE_TABLE = "upgrade";
protected static final String STACK_TABLE = "stack";
protected static final String CLUSTER_TABLE = "clusters";
protected static final String CLUSTER_UPGRADE_ID_COLUMN = "upgrade_id";
protected static final String YARN_ENV_CONFIG = "yarn-env";
protected static final String CAPACITY_SCHEDULER_CONFIG = "capacity-scheduler";
protected static final String WEBHCAT_SITE_CONFIG = "webhcat-site";
protected static final String TEZ_SITE_CONFIG = "tez-site";
protected static final String MAPRED_SITE_CONFIG = "mapred-site";
public static final String DESIRED_VERSION_COLUMN_NAME = "desired_version";
public static final String BLUEPRINT_SETTING_TABLE = "blueprint_setting";
public static final String BLUEPRINT_NAME_COL = "blueprint_name";
public static final String SETTING_NAME_COL = "setting_name";
public static final String SETTING_DATA_COL = "setting_data";
public static final String ID = "id";
public static final String BLUEPRINT_TABLE = "blueprint";
public static final String VIEWINSTANCE_TABLE = "viewinstance";
public static final String SHORT_URL_COLUMN = "short_url";
public static final String CLUSTER_HANDLE_COLUMN = "cluster_handle";
public static final String REQUESTSCHEDULE_TABLE = "requestschedule";
public static final String AUTHENTICATED_USER_ID_COLUMN = "authenticated_user_id";
protected static final String CLUSTER_VERSION_TABLE = "cluster_version";
protected static final String HOST_VERSION_TABLE = "host_version";
protected static final String TOPOLOGY_REQUEST_TABLE = "topology_request";
protected static final String PROVISION_ACTION_COL = "provision_action";
protected static final String PHOENIX_QUERY_SERVER_PRINCIPAL_KEY = "phoenix.queryserver.kerberos.principal";
protected static final String PHOENIX_QUERY_SERVER_KEYTAB_KEY = "phoenix.queryserver.keytab.file";
protected static final String DEFAULT_CONFIG_VERSION = "version1";
protected static final String SLIDER_SERVICE_NAME = "SLIDER";
private static final String OOZIE_ENV_CONFIG = "oozie-env";
private static final String SLIDER_CLIENT_CONFIG = "slider-client";
private static final String HIVE_ENV_CONFIG = "hive-env";
private static final String AMS_SITE = "ams-site";
public static final String TIMELINE_METRICS_SINK_COLLECTION_PERIOD = "timeline.metrics.sink.collection.period";
public static final String ONE_DIR_PER_PARITION_PROPERTY = "one_dir_per_partition";
public static final String VIEWURL_TABLE = "viewurl";
public static final String URL_ID_COLUMN = "url_id";
private static final String PRINCIPAL_TYPE_TABLE = "adminprincipaltype";
private static final String PRINCIPAL_TABLE = "adminprincipal";
protected static final String HBASE_SITE_CONFIG = "hbase-site";
protected static final String HBASE_SPNEGO_PRINCIPAL_KEY = "hbase.security.authentication.spnego.kerberos.principal";
protected static final String HBASE_SPNEGO_KEYTAB_KEY = "hbase.security.authentication.spnego.kerberos.keytab";
protected static final String EXTENSION_TABLE = "extension";
protected static final String EXTENSION_ID_COLUMN = "extension_id";
protected static final String EXTENSION_LINK_TABLE = "extensionlink";
protected static final String EXTENSION_LINK_ID_COLUMN = "link_id";
private static final Map<String, Integer> ROLE_ORDER;
public static final String WEBHCAT_SITE_QUEUE_NAME = "templeton.hadoop.queue.name";
public static final String TEZ_SITE_QUEUE_NAME = "tez.queue.name";
public static final String YARN_ENV_QUEUE_NAME = "service_check.queue.name";
public static final String MAPRED_SITE_QUEUE_NAME = "mapreduce.job.queuename";
private static final String AMS_HBASE_SITE = "ams-hbase-site";
private static final String HBASE_RPC_TIMEOUT_PROPERTY = "hbase.rpc.timeout";
private static final String AMS_HBASE_SITE_NORMALIZER_ENABLED_PROPERTY = "hbase.normalizer.enabled";
static {
// Manually create role order since there really isn't any mechanism for this
ROLE_ORDER = new HashMap<String, Integer>();
ROLE_ORDER.put("AMBARI.ADMINISTRATOR", 1);
ROLE_ORDER.put("CLUSTER.ADMINISTRATOR", 2);
ROLE_ORDER.put("CLUSTER.OPERATOR", 3);
ROLE_ORDER.put("SERVICE.ADMINISTRATOR", 4);
ROLE_ORDER.put("SERVICE.OPERATOR", 5);
ROLE_ORDER.put("CLUSTER.USER", 6);
}
@Inject
UserDAO userDAO;
@Inject
PermissionDAO permissionDAO;
@Inject
PrivilegeDAO privilegeDAO;
@Inject
ResourceTypeDAO resourceTypeDAO;
@Inject
ClusterDAO clusterDAO;
@Inject
PrincipalTypeDAO principalTypeDAO;
@Inject
PrincipalDAO principalDAO;
@Inject
RequestScheduleDAO requestScheduleDAO;
@Inject
Users users;
@Inject
Configuration config;
/**
* Logger.
*/
private static final Logger LOG = LoggerFactory.getLogger(UpgradeCatalog240.class);
private static final String SETTING_TABLE = "setting";
protected static final String SERVICE_COMPONENT_DESIRED_STATE_TABLE = "servicecomponentdesiredstate";
protected static final String RECOVERY_ENABLED_COL = "recovery_enabled";
// ----- Constructors ------------------------------------------------------
/**
* Don't forget to register new UpgradeCatalogs in {@link org.apache.ambari.server.upgrade.SchemaUpgradeHelper.UpgradeHelperModule#configure()}
*
* @param injector Guice injector to track dependencies and uses bindings to inject them.
*/
@Inject
public UpgradeCatalog240(Injector injector) {
super(injector);
injector.injectMembers(this);
}
// ----- UpgradeCatalog ----------------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public String getTargetVersion() {
return "2.4.0";
}
// ----- AbstractUpgradeCatalog --------------------------------------------
/**
* {@inheritDoc}
*/
@Override
public String getSourceVersion() {
return "2.3.0";
}
public static final String CLUSTER_TYPE_COLUMN = "cluster_type";
public static final String REMOTE_AMBARI_CLUSTER_TABLE = "remoteambaricluster";
public static final String REMOTE_AMBARI_CLUSTER_SERVICE_TABLE = "remoteambariclusterservice";
public static final String CLUSTER_ID = "cluster_id";
public static final String SERVICE_NAME = "service_name";
public static final String CLUSTER_NAME = "name";
@Override
protected void executeDDLUpdates() throws AmbariException, SQLException {
updateAdminPermissionTable();
updateServiceComponentDesiredStateTable();
createExtensionTable();
createExtensionLinkTable();
createSettingTable();
updateRepoVersionTableDDL();
updateServiceComponentDesiredStateTableDDL();
createServiceComponentHistoryTable();
updateClusterTableDDL();
updateAlertDefinitionTable();
updateAlertCurrentTable();
updateAlertTargetTable();
createBlueprintSettingTable();
updateHostRoleCommandTableDDL();
createViewUrlTableDDL();
updateViewInstanceEntityTable();
createRemoteClusterTable();
updateViewInstanceTable();
updateRequestScheduleEntityTable();
updateTopologyRequestTable();
}
private void createRemoteClusterTable() throws SQLException {
List<DBColumnInfo> columns = new ArrayList<>();
LOG.info("Creating {} table", REMOTE_AMBARI_CLUSTER_TABLE);
columns.add(new DBColumnInfo(CLUSTER_ID, Long.class, null, null, false));
columns.add(new DBColumnInfo(CLUSTER_NAME, String.class, 255, null, false));
columns.add(new DBColumnInfo("url", String.class, 255, null, false));
columns.add(new DBColumnInfo("username", String.class, 255, null, false));
columns.add(new DBColumnInfo("password", String.class, 255, null, false));
dbAccessor.createTable(REMOTE_AMBARI_CLUSTER_TABLE, columns, CLUSTER_ID);
dbAccessor.addUniqueConstraint(REMOTE_AMBARI_CLUSTER_TABLE , "UQ_remote_ambari_cluster" , CLUSTER_NAME);
addSequence("remote_cluster_id_seq", 1L, false);
List<DBColumnInfo> remoteClusterServiceColumns = new ArrayList<>();
LOG.info("Creating {} table", REMOTE_AMBARI_CLUSTER_SERVICE_TABLE);
remoteClusterServiceColumns.add(new DBColumnInfo(ID, Long.class, null, null, false));
remoteClusterServiceColumns.add(new DBColumnInfo(SERVICE_NAME, String.class, 255, null, false));
remoteClusterServiceColumns.add(new DBColumnInfo(CLUSTER_ID, Long.class, null, null, false));
dbAccessor.createTable(REMOTE_AMBARI_CLUSTER_SERVICE_TABLE, remoteClusterServiceColumns, ID);
dbAccessor.addFKConstraint(REMOTE_AMBARI_CLUSTER_SERVICE_TABLE, "FK_remote_ambari_cluster_id",
CLUSTER_ID, REMOTE_AMBARI_CLUSTER_TABLE, CLUSTER_ID, false);
addSequence("remote_cluster_service_id_seq", 1L, false);
}
private void createViewUrlTableDDL() throws SQLException {
List<DBColumnInfo> columns = new ArrayList<>();
// Add setting table
LOG.info("Creating " + VIEWURL_TABLE + " table");
columns.add(new DBColumnInfo(URL_ID_COLUMN, Long.class, null, null, false));
columns.add(new DBColumnInfo("url_name", String.class, 255, null, false));
columns.add(new DBColumnInfo("url_suffix", String.class, 255, null, false));
dbAccessor.createTable(VIEWURL_TABLE, columns, URL_ID_COLUMN);
addSequence("viewurl_id_seq", 1L, false);
}
private void updateViewInstanceEntityTable() throws SQLException {
dbAccessor.addColumn(VIEWINSTANCE_TABLE,
new DBColumnInfo(SHORT_URL_COLUMN, Long.class, null, null, true));
dbAccessor.addFKConstraint(VIEWINSTANCE_TABLE, "FK_instance_url_id",
SHORT_URL_COLUMN, VIEWURL_TABLE, URL_ID_COLUMN, false);
dbAccessor.addColumn(VIEWINSTANCE_TABLE,
new DBColumnInfo(CLUSTER_TYPE_COLUMN, String.class, 100, ClusterType.LOCAL_AMBARI.name(), false));
}
private void updateRequestScheduleEntityTable() throws SQLException {
dbAccessor.addColumn(REQUESTSCHEDULE_TABLE,
new DBColumnInfo(AUTHENTICATED_USER_ID_COLUMN, Integer.class, null, null, true));
}
private void updateClusterTableDDL() throws SQLException {
dbAccessor.addColumn(CLUSTER_TABLE, new DBColumnInfo(CLUSTER_UPGRADE_ID_COLUMN, Long.class, null, null, true));
dbAccessor.addFKConstraint(CLUSTER_TABLE, "FK_clusters_upgrade_id",
CLUSTER_UPGRADE_ID_COLUMN, UPGRADE_TABLE, "upgrade_id", false);
}
@Override
protected void executePreDMLUpdates() throws AmbariException, SQLException {
//To change body of implemented methods use File | Settings | File Templates.
}
@Override
protected void executeDMLUpdates() throws AmbariException, SQLException {
addNewConfigurationsFromXml();
updateAlerts();
setRoleSortOrder();
addSettingPermission();
addViewOperationalLogsPermission();
addManageUserPersistedDataPermission();
allowClusterOperatorToManageCredentials();
updateHDFSConfigs();
updateHIVEConfigs();
updateAMSConfigs();
updateClusterEnv();
updateSequenceForView();
updateHostRoleCommandTableDML();
updateKerberosConfigs();
updateYarnEnv();
updatePhoenixConfigs();
updateSparkConfigs();
updateHBaseConfigs();
updateFalconConfigs();
updateQueueNameConfigs();
updateKerberosDescriptorArtifacts();
removeHiveOozieDBConnectionConfigs();
updateClustersAndHostsVersionStateTableDML();
removeStandardDeviationAlerts();
removeAtlasMetaserverAlert();
updateClusterInheritedPermissionsConfig();
consolidateUserRoles();
createRolePrincipals();
updateHDFSWidgetDefinition();
updateTezViewProperty();
upgradeCapSchedulerView();
fixAuthorizationDescriptions();
removeAuthorizations();
addConnectionTimeoutParamForWebAndMetricAlerts();
addSliderClientConfig();
updateRequestScheduleEntityUserIds();
updateRecoveryConfigurationDML();
updatePigSmokeTestEntityClass();
updateRangerHbasePluginProperties();
}
/**
* Populates authenticated_user_id field by correct user id calculated from user name
* @throws SQLException
*/
protected void updateRequestScheduleEntityUserIds() throws SQLException {
List<RequestScheduleEntity> requestScheduleEntities = requestScheduleDAO.findAll();
for (RequestScheduleEntity requestScheduleEntity : requestScheduleEntities) {
String createdUserName = requestScheduleEntity.getCreateUser();
if (createdUserName != null) {
User user = users.getUserIfUnique(createdUserName);
if (user != null && StringUtils.equals(user.getUserName(), createdUserName)) {
requestScheduleEntity.setAuthenticatedUserId(user.getUserId());
requestScheduleDAO.merge(requestScheduleEntity);
}
}
}
}
protected void updateClusterInheritedPermissionsConfig() throws SQLException {
insertClusterInheritedPrincipal("ALL.CLUSTER.ADMINISTRATOR");
insertClusterInheritedPrincipal("ALL.CLUSTER.OPERATOR");
insertClusterInheritedPrincipal("ALL.CLUSTER.USER");
insertClusterInheritedPrincipal("ALL.SERVICE.ADMINISTRATOR");
insertClusterInheritedPrincipal("ALL.SERVICE.OPERATIOR");
}
private void insertClusterInheritedPrincipal(String name) {
PrincipalTypeEntity principalTypeEntity = new PrincipalTypeEntity();
principalTypeEntity.setName(name);
principalTypeEntity = principalTypeDAO.merge(principalTypeEntity);
PrincipalEntity principalEntity = new PrincipalEntity();
principalEntity.setPrincipalType(principalTypeEntity);
principalDAO.create(principalEntity);
}
private static final String NAME_PREFIX = "DS_";
private String getEntityName(ViewEntityEntity entity) {
String className = entity.getClassName();
String[] parts = className.split("\\.");
String simpleClassName = parts[parts.length - 1];
if (entity.getViewInstance().alterNames()) {
return NAME_PREFIX + simpleClassName + "_" + entity.getId();
}
return simpleClassName + entity.getId();
}
/**
* get all entries of viewentity
* find all the table names by parsing class_name
* create all the sequence names by appending _id_seq
* query each dynamic table to find the max of id
* insert into ambari_sequence name and counter for each item
*/
protected void updateSequenceForView() {
LOG.info("updateSequenceForView called.");
EntityManager entityManager = getEntityManagerProvider().get();
TypedQuery<ViewEntityEntity> viewEntityQuery = entityManager.createQuery("SELECT vee FROM ViewEntityEntity vee", ViewEntityEntity.class);
List<ViewEntityEntity> viewEntities = viewEntityQuery.getResultList();
LOG.info("Received view Entities : {}, length : {}", viewEntities, viewEntities.size());
// as the id fields are string in these entities we will have to get all ids and convert to int and find max.
String selectIdsFormat = "select %s from %s";
String insertQuery = "insert into ambari_sequences values ('%s',%d)";
for (ViewEntityEntity viewEntity : viewEntities) {
LOG.info("Working with viewEntity : {} : {} ", viewEntity, viewEntity.getViewName() + viewEntity.getViewInstance());
String tableName = getEntityName(viewEntity);
String seqName = tableName.toLowerCase() + "_id_seq";
try {
entityManager.getTransaction().begin();
String selectIdsQueryString = String.format(selectIdsFormat, NAME_PREFIX + viewEntity.getIdProperty(), tableName).toLowerCase();
LOG.info("executing max query string {}", selectIdsQueryString);
Query selectIdsQuery = entityManager.createNativeQuery(selectIdsQueryString);
List<String> ids = selectIdsQuery.getResultList();
LOG.info("Received ids : {}", ids);
int maxId = 0;
if (null != ids && ids.size() != 0) {
for (String id : ids) {
try {
Integer intId = Integer.parseInt(id);
maxId = Math.max(intId, maxId);
} catch (NumberFormatException e) {
LOG.error("the id was non integer : id : {}. So ignoring.", id);
}
}
}
String insertQueryString = String.format(insertQuery, seqName, maxId).toLowerCase();
LOG.info("Executing insert query : {}", insertQueryString);
Query insertQ = entityManager.createNativeQuery(insertQueryString);
int rowsChanged = insertQ.executeUpdate();
entityManager.getTransaction().commit();
LOG.info("executing insert resulted in {} row changes.", rowsChanged);
} catch (Exception e) { // when the entity table is not yet created or other exception.
entityManager.getTransaction().rollback();
LOG.info("Error (can be ignored) {}", e.getMessage());
LOG.debug("Exception occured while updating : {}",viewEntity.getViewName() + viewEntity.getViewInstance(), e);
}
}
}
private void createExtensionTable() throws SQLException {
List<DBColumnInfo> columns = new ArrayList<>();
// Add extension table
LOG.info("Creating " + EXTENSION_TABLE + " table");
columns.add(new DBColumnInfo(EXTENSION_ID_COLUMN, Long.class, null, null, false));
columns.add(new DBColumnInfo("extension_name", String.class, 255, null, false));
columns.add(new DBColumnInfo("extension_version", String.class, 255, null, false));
dbAccessor.createTable(EXTENSION_TABLE, columns, EXTENSION_ID_COLUMN);
// create UNIQUE constraint, ensuring column order matches SQL files
String[] uniqueColumns = new String[] { "extension_name", "extension_version" };
dbAccessor.addUniqueConstraint(EXTENSION_TABLE, "UQ_extension", uniqueColumns);
addSequence("extension_id_seq", 0L, false);
}
private void createExtensionLinkTable() throws SQLException {
List<DBColumnInfo> columns = new ArrayList<>();
// Add extension link table
LOG.info("Creating " + EXTENSION_LINK_TABLE + " table");
columns.add(new DBColumnInfo(EXTENSION_LINK_ID_COLUMN, Long.class, null, null, false));
columns.add(new DBColumnInfo("stack_id", Long.class, null, null, false));
columns.add(new DBColumnInfo(EXTENSION_ID_COLUMN, Long.class, null, null, false));
dbAccessor.createTable(EXTENSION_LINK_TABLE, columns, EXTENSION_LINK_ID_COLUMN);
// create UNIQUE constraint, ensuring column order matches SQL files
String[] uniqueColumns = new String[] { "stack_id", EXTENSION_ID_COLUMN };
dbAccessor.addUniqueConstraint(EXTENSION_LINK_TABLE, "UQ_extension_link", uniqueColumns);
dbAccessor.addFKConstraint(EXTENSION_LINK_TABLE, "FK_extensionlink_extension_id",
EXTENSION_ID_COLUMN, EXTENSION_TABLE, EXTENSION_ID_COLUMN, false);
dbAccessor.addFKConstraint(EXTENSION_LINK_TABLE, "FK_extensionlink_stack_id",
"stack_id", STACK_TABLE, "stack_id", false);
addSequence("link_id_seq", 0L, false);
}
private void createSettingTable() throws SQLException {
List<DBColumnInfo> columns = new ArrayList<>();
// Add setting table
LOG.info("Creating " + SETTING_TABLE + " table");
columns.add(new DBColumnInfo(ID, Long.class, null, null, false));
columns.add(new DBColumnInfo("name", String.class, 255, null, false));
columns.add(new DBColumnInfo("setting_type", String.class, 255, null, false));
columns.add(new DBColumnInfo("content", String.class, 3000, null, false));
columns.add(new DBColumnInfo("updated_by", String.class, 255, "_db", false));
columns.add(new DBColumnInfo("update_timestamp", Long.class, null, null, false));
dbAccessor.createTable(SETTING_TABLE, columns, ID);
addSequence("setting_id_seq", 0L, false);
}
protected void addSettingPermission() throws SQLException {
addRoleAuthorization("AMBARI.MANAGE_SETTINGS", "Manage settings", Collections.singleton("AMBARI.ADMINISTRATOR:AMBARI"));
}
protected void addViewOperationalLogsPermission() throws SQLException {
Collection<String> roles = Arrays.asList(
"AMBARI.ADMINISTRATOR:AMBARI",
"CLUSTER.ADMINISTRATOR:CLUSTER",
"CLUSTER.OPERATOR:CLUSTER",
"SERVICE.ADMINISTRATOR:CLUSTER");
addRoleAuthorization("SERVICE.VIEW_OPERATIONAL_LOGS", "View service operational logs", roles);
}
/**
* Add 'MANAGE_USER_PERSISTED_DATA' permissions for CLUSTER.ADMINISTRATOR, SERVICE.OPERATOR, SERVICE.ADMINISTRATOR,
* CLUSTER.OPERATOR, AMBARI.ADMINISTRATOR.
*
*/
protected void addManageUserPersistedDataPermission() throws SQLException {
Collection<String> roles = Arrays.asList(
"AMBARI.ADMINISTRATOR:AMBARI",
"CLUSTER.ADMINISTRATOR:CLUSTER",
"CLUSTER.OPERATOR:CLUSTER",
"SERVICE.ADMINISTRATOR:CLUSTER",
"SERVICE.OPERATOR:CLUSTER",
"CLUSTER.USER:CLUSTER");
addRoleAuthorization("CLUSTER.MANAGE_USER_PERSISTED_DATA", "Manage cluster-level user persisted data", roles);
}
/**
* Adds <code>CLUSTER.MANAGE_CREDENTIALS</code> to the set of authorizations a <code>CLUSTER.OPERATOR</code> can perform.
*
* @throws SQLException
*/
protected void allowClusterOperatorToManageCredentials() throws SQLException {
addAuthorizationToRole("CLUSTER.OPERATOR", "CLUSTER", "CLUSTER.MANAGE_CREDENTIAL");
}
protected void removeHiveOozieDBConnectionConfigs() throws AmbariException {
AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
Map<String, Cluster> clusterMap = getCheckedClusterMap(ambariManagementController.getClusters());
for (final Cluster cluster : clusterMap.values()) {
Config oozieEnv = cluster.getDesiredConfigByType(OOZIE_ENV_CONFIG);
if(oozieEnv != null) {
Map<String, String> oozieEnvProperties = oozieEnv.getProperties();
Set<String> removePropertiesSet = new HashSet<>();
if (oozieEnvProperties.containsKey("oozie_derby_database")) {
LOG.info("Removing property oozie_derby_database from " + OOZIE_ENV_CONFIG);
removePropertiesSet.add("oozie_derby_database");
}
if (oozieEnvProperties.containsKey("oozie_hostname")) {
LOG.info("Removing property oozie_hostname from " + OOZIE_ENV_CONFIG);
removePropertiesSet.add("oozie_hostname");
}
if (!removePropertiesSet.isEmpty()) {
removeConfigurationPropertiesFromCluster(cluster, OOZIE_ENV_CONFIG, removePropertiesSet);
}
}
Config hiveEnv = cluster.getDesiredConfigByType(HIVE_ENV_CONFIG);
if(hiveEnv != null) {
Map<String, String> hiveEnvProperties = hiveEnv.getProperties();
if (hiveEnvProperties.containsKey("hive_hostname")) {
LOG.info("Removing property hive_hostname from " + HIVE_ENV_CONFIG);
removeConfigurationPropertiesFromCluster(cluster, HIVE_ENV_CONFIG, Collections.singleton("hive_hostname"));
}
}
}
}
protected void addSliderClientConfig() throws AmbariException {
AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
Clusters clusters = ambariManagementController.getClusters();
ConfigHelper configHelper = ambariManagementController.getConfigHelper();
Map<String, Cluster> clusterMap = getCheckedClusterMap(clusters);
for (final Cluster cluster : clusterMap.values()) {
Set<String> installedServices = cluster.getServices().keySet();
if (installedServices.contains(SLIDER_SERVICE_NAME)) {
Config sliderClientConfig = cluster.getDesiredConfigByType(SLIDER_CLIENT_CONFIG);
if (sliderClientConfig == null) {
configHelper.createConfigType(cluster, ambariManagementController, SLIDER_CLIENT_CONFIG,
new HashMap<String, String>(), AUTHENTICATED_USER_NAME, "");
}
}
}
}
protected void updateAlerts() {
// map of alert_name -> property_name -> visibility_value
final Map<String, String> hdfsVisibilityMap = new HashMap<String, String>(){{
put("mergeHaMetrics", "HIDDEN");
put("appId", "HIDDEN");
put("metricName", "HIDDEN");
}};
final Map<String, String> defaultKeytabVisibilityMap = new HashMap<String, String>(){{
put("default.smoke.principal", "HIDDEN");
put("default.smoke.keytab", "HIDDEN");
}};
final Map<String, String> percentParameterMap = new HashMap<String, String>(){{
put("units", "%");
put("type", "PERCENT");
}};
Map<String, Map<String, String>> visibilityMap = new HashMap<String, Map<String, String>>(){{
put("hive_webhcat_server_status", new HashMap<String, String>(){{
put("default.smoke.user", "HIDDEN");
}});
put("hive_metastore_process", defaultKeytabVisibilityMap);
put("hive_server_process", defaultKeytabVisibilityMap);
put("zookeeper_server_process", new HashMap<String, String>(){{
put("socket.command", "HIDDEN");
put("socket.command.response", "HIDDEN");
}});
}};
Map<String, Map<String, String>> reportingPercentMap = new HashMap<String, Map<String, String>>(){{
put("hawq_segment_process_percent", percentParameterMap);
put("mapreduce_history_server_cpu", percentParameterMap);
put("yarn_nodemanager_webui_percent", percentParameterMap);
put("yarn_resourcemanager_cpu", percentParameterMap);
put("datanode_process_percent", percentParameterMap);
put("datanode_storage_percent", percentParameterMap);
put("journalnode_process_percent", percentParameterMap);
put("namenode_cpu", percentParameterMap);
put("namenode_hdfs_capacity_utilization", percentParameterMap);
put("datanode_storage", percentParameterMap);
put("datanode_heap_usage", percentParameterMap);
put("storm_supervisor_process_percent", percentParameterMap);
put("hbase_regionserver_process_percent", percentParameterMap);
put("hbase_master_cpu", percentParameterMap);
put("zookeeper_server_process_percent", percentParameterMap);
put("metrics_monitor_process_percent", percentParameterMap);
put("ams_metrics_collector_hbase_master_cpu", percentParameterMap);
}};
Map<String, Map<String, Integer>> reportingMultiplierMap = new HashMap<String, Map<String, Integer>>(){{
put("hawq_segment_process_percent", new HashMap<String, Integer>() {{
put("warning", 100);
put("critical", 100);
}});
put("yarn_nodemanager_webui_percent", new HashMap<String, Integer>() {{
put("warning", 100);
put("critical", 100);
}});
put("datanode_process_percent", new HashMap<String, Integer>() {{
put("warning", 100);
put("critical", 100);
}});
put("datanode_storage_percent", new HashMap<String, Integer>() {{
put("warning", 100);
put("critical", 100);
}});
put("journalnode_process_percent", new HashMap<String, Integer>() {{
put("warning", 100);
put("critical", 100);
}});
put("storm_supervisor_process_percent", new HashMap<String, Integer>() {{
put("warning", 100);
put("critical", 100);
}});
put("hbase_regionserver_process_percent", new HashMap<String, Integer>() {{
put("warning", 100);
put("critical", 100);
}});
put("zookeeper_server_process_percent", new HashMap<String, Integer>() {{
put("warning", 100);
put("critical", 100);
}});
put("metrics_monitor_process_percent", new HashMap<String, Integer>() {{
put("warning", 100);
put("critical", 100);
}});
}};
Map<String, Map<String, Integer>> scriptAlertMultiplierMap = new HashMap<String, Map<String, Integer>>(){{
put("ambari_agent_disk_usage", new HashMap<String, Integer>() {{
put("percent.used.space.warning.threshold", 100);
put("percent.free.space.critical.threshold", 100);
}});
put("namenode_last_checkpoint", new HashMap<String, Integer>() {{
put("checkpoint.time.warning.threshold", 100);
put("checkpoint.time.critical.threshold", 100);
}});
}};
String newNameservicePropertyValue = "{{hdfs-site/dfs.internal.nameservices}}";
final Set<String> alertNamesForNameserviceUpdate = new HashSet<String>() {{
add("namenode_webui");
add("namenode_hdfs_blocks_health");
add("namenode_hdfs_pending_deletion_blocks");
add("namenode_rpc_latency");
add("namenode_directory_status");
add("datanode_health_summary");
add("namenode_cpu");
add("namenode_hdfs_capacity_utilization");
}};
// list of alerts that need to get property updates
Set<String> alertNamesForPropertyUpdates = new HashSet<String>() {{
add("hawq_segment_process_percent");
add("mapreduce_history_server_cpu");
add("yarn_nodemanager_webui_percent");
add("yarn_resourcemanager_cpu");
add("datanode_process_percent");
add("datanode_storage_percent");
add("journalnode_process_percent");
add("namenode_cpu");
add("namenode_hdfs_capacity_utilization");
add("datanode_storage");
add("datanode_heap_usage");
add("storm_supervisor_process_percent");
add("hbase_regionserver_process_percent");
add("hbase_master_cpu");
add("zookeeper_server_process_percent");
add("metrics_monitor_process_percent");
add("ams_metrics_collector_hbase_master_cpu");
add("ambari_agent_disk_usage");
add("namenode_last_checkpoint");
addAll(alertNamesForNameserviceUpdate);
}};
// list of alerts to be removed
Set<String> alertForRemoval = new HashSet<String>() {{
add("storm_rest_api");
add("mapreduce_history_server_process");
}};
LOG.info("Updating alert definitions.");
AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
AlertDefinitionDAO alertDefinitionDAO = injector.getInstance(AlertDefinitionDAO.class);
Clusters clusters = ambariManagementController.getClusters();
Map<String, Cluster> clusterMap = getCheckedClusterMap(clusters);
for (final Cluster cluster : clusterMap.values()) {
long clusterID = cluster.getClusterId();
// here goes alerts that need get new properties
final AlertDefinitionEntity namenodeLastCheckpointAlertDefinitionEntity = alertDefinitionDAO.findByName(
clusterID, "namenode_last_checkpoint");
final AlertDefinitionEntity namenodeHAHealthAlertDefinitionEntity = alertDefinitionDAO.findByName(
clusterID, "namenode_ha_health");
final AlertDefinitionEntity nodemanagerHealthAlertDefinitionEntity = alertDefinitionDAO.findByName(
clusterID, "yarn_nodemanager_health");
final AlertDefinitionEntity nodemanagerHealthSummaryAlertDefinitionEntity = alertDefinitionDAO.findByName(
clusterID, "nodemanager_health_summary");
final AlertDefinitionEntity hiveMetastoreProcessAlertDefinitionEntity = alertDefinitionDAO.findByName(
clusterID, "hive_metastore_process");
final AlertDefinitionEntity hiveServerProcessAlertDefinitionEntity = alertDefinitionDAO.findByName(
clusterID, "hive_server_process");
final AlertDefinitionEntity hiveWebhcatServerStatusAlertDefinitionEntity = alertDefinitionDAO.findByName(
clusterID, "hive_webhcat_server_status");
final AlertDefinitionEntity flumeAgentStatusAlertDefinitionEntity = alertDefinitionDAO.findByName(
clusterID, "flume_agent_status");
final AlertDefinitionEntity zookeeperServerProcessAlertDefinitionEntity = alertDefinitionDAO.findByName(
clusterID, "zookeeper_server_process");
Map<AlertDefinitionEntity, List<String>> alertDefinitionParams = new HashMap<>();
checkedPutToMap(alertDefinitionParams, namenodeLastCheckpointAlertDefinitionEntity,
Lists.newArrayList("connection.timeout", "checkpoint.time.warning.threshold",
"checkpoint.time.critical.threshold", "checkpoint.txns.multiplier.warning.threshold",
"checkpoint.txns.multiplier.critical.threshold"));
checkedPutToMap(alertDefinitionParams, namenodeHAHealthAlertDefinitionEntity,
Lists.newArrayList("connection.timeout"));
checkedPutToMap(alertDefinitionParams, nodemanagerHealthAlertDefinitionEntity,
Lists.newArrayList("connection.timeout"));
checkedPutToMap(alertDefinitionParams, nodemanagerHealthSummaryAlertDefinitionEntity,
Lists.newArrayList("connection.timeout"));
checkedPutToMap(alertDefinitionParams, hiveMetastoreProcessAlertDefinitionEntity,
Lists.newArrayList("default.smoke.user", "default.smoke.principal", "default.smoke.keytab"));
checkedPutToMap(alertDefinitionParams, hiveServerProcessAlertDefinitionEntity,
Lists.newArrayList("default.smoke.user", "default.smoke.principal", "default.smoke.keytab"));
checkedPutToMap(alertDefinitionParams, hiveWebhcatServerStatusAlertDefinitionEntity,
Lists.newArrayList("default.smoke.user", "connection.timeout"));
checkedPutToMap(alertDefinitionParams, flumeAgentStatusAlertDefinitionEntity,
Lists.newArrayList("run.directory"));
checkedPutToMap(alertDefinitionParams, zookeeperServerProcessAlertDefinitionEntity,
Lists.newArrayList("socket.command", "socket.command.response"));
Map<Long, AlertDefinitionEntity> definitionsForPropertyUpdates = new HashMap<>();
// adding new properties
for (Map.Entry<AlertDefinitionEntity, List<String>> entry : alertDefinitionParams.entrySet()){
AlertDefinitionEntity alertDefinition = entry.getKey();
String source = alertDefinition.getSource();
alertDefinition.setSource(addParam(source, entry.getValue()));
definitionsForPropertyUpdates.put(alertDefinition.getDefinitionId(), alertDefinition);
}
// here goes alerts that need update for existing properties
for (String name : alertNamesForPropertyUpdates) {
AlertDefinitionEntity alertDefinition = alertDefinitionDAO.findByName(clusterID, name);
if (alertDefinition != null && !definitionsForPropertyUpdates.containsKey(alertDefinition.getDefinitionId())) {
definitionsForPropertyUpdates.put(alertDefinition.getDefinitionId(), alertDefinition);
}
}
// updating old and new properties, best way to use map like visibilityMap.
for (AlertDefinitionEntity alertDefinition : definitionsForPropertyUpdates.values()) {
// here goes property updates
if (visibilityMap.containsKey(alertDefinition.getDefinitionName())) {
for (Map.Entry<String, String> entry : visibilityMap.get(alertDefinition.getDefinitionName()).entrySet()){
String paramName = entry.getKey();
String visibilityValue = entry.getValue();
String source = alertDefinition.getSource();
alertDefinition.setSource(addParamOption(source, paramName, "visibility", visibilityValue));
}
}
// update percent script alerts param values from 0.x to 0.x * 100 values
if (scriptAlertMultiplierMap.containsKey(alertDefinition.getDefinitionName())) {
for (Map.Entry<String, Integer> entry : scriptAlertMultiplierMap.get(alertDefinition.getDefinitionName()).entrySet()){
String paramName = entry.getKey();
Integer multiplier = entry.getValue();
String source = alertDefinition.getSource();
Float oldValue = getParamFloatValue(source, paramName);
if (oldValue == null) {
alertDefinition.setSource(addParam(source, Arrays.asList(paramName)));
} else {
Integer newValue = Math.round(oldValue * multiplier);
alertDefinition.setSource(setParamIntegerValue(source, paramName, newValue));
}
}
}
// update reporting alerts(aggregate and metrics) values from 0.x to 0.x * 100 values
if (reportingMultiplierMap.containsKey(alertDefinition.getDefinitionName())) {
for (Map.Entry<String, Integer> entry : reportingMultiplierMap.get(alertDefinition.getDefinitionName()).entrySet()){
String reportingName = entry.getKey();
Integer multiplier = entry.getValue();
String source = alertDefinition.getSource();
Float oldValue = getReportingFloatValue(source, reportingName);
Integer newValue = Math.round(oldValue * multiplier);
alertDefinition.setSource(setReportingIntegerValue(source, reportingName, newValue));
}
}
if (reportingPercentMap.containsKey(alertDefinition.getDefinitionName())) {
for (Map.Entry<String, String> entry : reportingPercentMap.get(alertDefinition.getDefinitionName()).entrySet()){
String paramName = entry.getKey();
String paramValue = entry.getValue();
String source = alertDefinition.getSource();
alertDefinition.setSource(addReportingOption(source, paramName, paramValue));
}
}
if (alertNamesForNameserviceUpdate.contains(alertDefinition.getDefinitionName())) {
String source = alertDefinition.getSource();
alertDefinition.setSource(setNameservice(source, newNameservicePropertyValue));
}
// regeneration of hash and writing modified alerts to database, must go after all modifications finished
alertDefinition.setHash(UUID.randomUUID().toString());
alertDefinitionDAO.merge(alertDefinition);
}
//update Atlas alert
final AlertDefinitionEntity atlasMetadataServerWebUI = alertDefinitionDAO.findByName(
clusterID, "metadata_server_webui");
if (atlasMetadataServerWebUI != null) {
String source = atlasMetadataServerWebUI.getSource();
JsonObject sourceJson = new JsonParser().parse(source).getAsJsonObject();
JsonObject uriJson = sourceJson.get("uri").getAsJsonObject();
uriJson.remove("kerberos_keytab");
uriJson.remove("kerberos_principal");
uriJson.addProperty("kerberos_keytab", "{{cluster-env/smokeuser_keytab}}");
uriJson.addProperty("kerberos_principal", "{{cluster-env/smokeuser_principal_name}}");
atlasMetadataServerWebUI.setSource(sourceJson.toString());
alertDefinitionDAO.merge(atlasMetadataServerWebUI);
}
for (String alertName: alertForRemoval) {
AlertDefinitionEntity alertDefinition = alertDefinitionDAO.findByName(clusterID, alertName);
if (alertDefinition != null) {
LOG.info("Removing alert : " + alertName);
alertDefinitionDAO.remove(alertDefinition);
}
}
}
}
protected String setNameservice(String source, String paramValue) {
final String nameservicePropertyName = "nameservice";
JsonObject sourceJson = new JsonParser().parse(source).getAsJsonObject();
JsonObject highAvailability = sourceJson.getAsJsonObject("uri").getAsJsonObject("high_availability");
if (highAvailability.has(nameservicePropertyName)) {
highAvailability.addProperty(nameservicePropertyName, paramValue);
}
return sourceJson.toString();
}
/*
* Simple put method with check for key is not null
* */
private void checkedPutToMap(Map<AlertDefinitionEntity, List<String>> alertDefinitionParams, AlertDefinitionEntity alertDefinitionEntity,
List<String> params) {
if (alertDefinitionEntity != null) {
alertDefinitionParams.put(alertDefinitionEntity, params);
}
}
/**
* Add option to script parameter.
* @param source json string of script source
* @param paramName parameter name
* @param optionName option name
* @param optionValue option value
* @return modified source
*/
protected String addParamOption(String source, String paramName, String optionName, String optionValue){
JsonObject sourceJson = new JsonParser().parse(source).getAsJsonObject();
JsonArray parametersJson = sourceJson.getAsJsonArray("parameters");
if(parametersJson != null && !parametersJson.isJsonNull()) {
for(JsonElement param : parametersJson) {
if(param.isJsonObject()) {
JsonObject paramObject = param.getAsJsonObject();
if(paramObject.has("name") && paramObject.get("name").getAsString().equals(paramName)){
paramObject.add(optionName, new JsonPrimitive(optionValue));
}
}
}
}
return sourceJson.toString();
}
/**
* Returns param value as float.
* @param source source of script alert
* @param paramName param name
* @return param value as float
*/
protected Float getParamFloatValue(String source, String paramName){
JsonObject sourceJson = new JsonParser().parse(source).getAsJsonObject();
JsonArray parametersJson = sourceJson.getAsJsonArray("parameters");
if(parametersJson != null && !parametersJson.isJsonNull()) {
for(JsonElement param : parametersJson) {
if(param.isJsonObject()) {
JsonObject paramObject = param.getAsJsonObject();
if(paramObject.has("name") && paramObject.get("name").getAsString().equals(paramName)){
if(paramObject.has("value")) {
return paramObject.get("value").getAsFloat();
}
}
}
}
}
return null;
}
/**
* Set integer param value.
* @param source source of script alert
* @param paramName param name
* @param value new param value
* @return modified source
*/
protected String setParamIntegerValue(String source, String paramName, Integer value){
JsonObject sourceJson = new JsonParser().parse(source).getAsJsonObject();
JsonArray parametersJson = sourceJson.getAsJsonArray("parameters");
if(parametersJson != null && !parametersJson.isJsonNull()) {
for(JsonElement param : parametersJson) {
if(param.isJsonObject()) {
JsonObject paramObject = param.getAsJsonObject();
if(paramObject.has("name") && paramObject.get("name").getAsString().equals(paramName)){
paramObject.add("value", new JsonPrimitive(value));
}
}
}
}
return sourceJson.toString();
}
/**
* Returns reporting value as float.
* @param source source of aggregate or metric alert
* @param reportingName reporting name, must be "warning" or "critical"
* @return reporting value as float
*/
protected Float getReportingFloatValue(String source, String reportingName){
JsonObject sourceJson = new JsonParser().parse(source).getAsJsonObject();
return sourceJson.getAsJsonObject("reporting").getAsJsonObject(reportingName).get("value").getAsFloat();
}
/**
* Set integer value of reporting.
* @param source source of aggregate or metric alert
* @param reportingName reporting name, must be "warning" or "critical"
* @param value new value
* @return modified source
*/
protected String setReportingIntegerValue(String source, String reportingName, Integer value){
JsonObject sourceJson = new JsonParser().parse(source).getAsJsonObject();
sourceJson.getAsJsonObject("reporting").getAsJsonObject(reportingName).add("value", new JsonPrimitive(value));
return sourceJson.toString();
}
/**
* Add option to reporting
* @param source source of aggregate or metric alert
* @param optionName option name
* @param value option value
* @return modified source
*/
protected String addReportingOption(String source, String optionName, String value){
JsonObject sourceJson = new JsonParser().parse(source).getAsJsonObject();
sourceJson.getAsJsonObject("reporting").add(optionName, new JsonPrimitive(value));
return sourceJson.toString();
}
protected String addParam(String source, List<String> params) {
JsonObject sourceJson = new JsonParser().parse(source).getAsJsonObject();
JsonArray parametersJson = sourceJson.getAsJsonArray("parameters");
boolean parameterExists = parametersJson != null && !parametersJson.isJsonNull();
if (parameterExists) {
Iterator<JsonElement> jsonElementIterator = parametersJson.iterator();
while (jsonElementIterator.hasNext()) {
JsonElement element = jsonElementIterator.next();
JsonElement name = element.getAsJsonObject().get("name");
if (name != null && !name.isJsonNull() && params.contains(name.getAsString())) {
params.remove(name.getAsString());
}
}
if (params.size() == 0) {
return sourceJson.toString();
}
}
List<JsonObject> paramsToAdd = new ArrayList<>();
if (params.contains("connection.timeout")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("connection.timeout"));
param.add("display_name", new JsonPrimitive("Connection Timeout"));
param.add("value", new JsonPrimitive(5.0));
param.add("type", new JsonPrimitive("NUMERIC"));
param.add("description", new JsonPrimitive("The maximum time before this alert is considered to be CRITICAL"));
param.add("units", new JsonPrimitive("seconds"));
param.add("threshold", new JsonPrimitive("CRITICAL"));
paramsToAdd.add(param);
}
if (params.contains("checkpoint.time.warning.threshold")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("checkpoint.time.warning.threshold"));
param.add("display_name", new JsonPrimitive("Checkpoint Warning"));
param.add("value", new JsonPrimitive(2.0));
param.add("type", new JsonPrimitive("PERCENT"));
param.add("description", new JsonPrimitive("The percentage of the last checkpoint time greater than the interval in order to trigger a warning alert."));
param.add("units", new JsonPrimitive("%"));
param.add("threshold", new JsonPrimitive("WARNING"));
paramsToAdd.add(param);
}
if (params.contains("checkpoint.time.critical.threshold")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("checkpoint.time.critical.threshold"));
param.add("display_name", new JsonPrimitive("Checkpoint Critical"));
param.add("value", new JsonPrimitive(4.0));
param.add("type", new JsonPrimitive("PERCENT"));
param.add("description", new JsonPrimitive("The percentage of the last checkpoint time greater than the interval in order to trigger a critical alert."));
param.add("units", new JsonPrimitive("%"));
param.add("threshold", new JsonPrimitive("CRITICAL"));
paramsToAdd.add(param);
}
if (params.contains("checkpoint.txns.multiplier.warning.threshold")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("checkpoint.txns.multiplier.warning.threshold"));
param.add("display_name", new JsonPrimitive("Uncommitted transactions Warning"));
param.add("value", new JsonPrimitive(2.0));
param.add("type", new JsonPrimitive("NUMERIC"));
param.add("description", new JsonPrimitive("The multiplier to use against dfs.namenode.checkpoint.period compared to the difference between last transaction id and most recent transaction id beyond which to trigger a warning alert."));
param.add("threshold", new JsonPrimitive("WARNING"));
paramsToAdd.add(param);
}
if (params.contains("checkpoint.txns.multiplier.critical.threshold")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("checkpoint.txns.multiplier.critical.threshold"));
param.add("display_name", new JsonPrimitive("Uncommitted transactions Critical"));
param.add("value", new JsonPrimitive(4.0));
param.add("type", new JsonPrimitive("NUMERIC"));
param.add("description", new JsonPrimitive("The multiplier to use against dfs.namenode.checkpoint.period compared to the difference between last transaction id and most recent transaction id beyond which to trigger a critical alert."));
param.add("threshold", new JsonPrimitive("CRITICAL"));
paramsToAdd.add(param);
}
if (params.contains("default.smoke.user")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("default.smoke.user"));
param.add("display_name", new JsonPrimitive("Default Smoke User"));
param.add("value", new JsonPrimitive("ambari-qa"));
param.add("type", new JsonPrimitive("STRING"));
param.add("description", new JsonPrimitive("The user that will run the Hive commands if not specified in cluster-env/smokeuser"));
paramsToAdd.add(param);
}
if (params.contains("default.smoke.principal")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("default.smoke.principal"));
param.add("display_name", new JsonPrimitive("Default Smoke Principal"));
param.add("value", new JsonPrimitive("ambari-qa@EXAMPLE.COM"));
param.add("type", new JsonPrimitive("STRING"));
param.add("description", new JsonPrimitive("The principal to use when retrieving the kerberos ticket if not specified in cluster-env/smokeuser_principal_name"));
paramsToAdd.add(param);
}
if (params.contains("default.smoke.keytab")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("default.smoke.keytab"));
param.add("display_name", new JsonPrimitive("Default Smoke Keytab"));
param.add("value", new JsonPrimitive("/etc/security/keytabs/smokeuser.headless.keytab"));
param.add("type", new JsonPrimitive("STRING"));
param.add("description", new JsonPrimitive("The keytab to use when retrieving the kerberos ticket if not specified in cluster-env/smokeuser_keytab"));
paramsToAdd.add(param);
}
if (params.contains("run.directory")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("run.directory"));
param.add("display_name", new JsonPrimitive("Run Directory"));
param.add("value", new JsonPrimitive("/var/run/flume"));
param.add("type", new JsonPrimitive("STRING"));
param.add("description", new JsonPrimitive("The directory where flume agent processes will place their PID files."));
paramsToAdd.add(param);
}
if (params.contains("minimum.free.space")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("minimum.free.space"));
param.add("display_name", new JsonPrimitive("Minimum Free Space"));
param.add("value", new JsonPrimitive("5000000000"));
param.add("type", new JsonPrimitive("NUMERIC"));
param.add("description", new JsonPrimitive("The overall amount of free disk space left before an alert is triggered."));
param.add("units", new JsonPrimitive("bytes"));
param.add("threshold", new JsonPrimitive("WARNING"));
paramsToAdd.add(param);
}
if (params.contains("percent.used.space.warning.threshold")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("percent.used.space.warning.threshold"));
param.add("display_name", new JsonPrimitive("Warning"));
param.add("value", new JsonPrimitive("50"));
param.add("type", new JsonPrimitive("PERCENT"));
param.add("description", new JsonPrimitive("The percent of disk space consumed before a warning is triggered."));
param.add("units", new JsonPrimitive("%"));
param.add("threshold", new JsonPrimitive("WARNING"));
paramsToAdd.add(param);
}
if (params.contains("percent.free.space.critical.threshold")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("percent.free.space.critical.threshold"));
param.add("display_name", new JsonPrimitive("Critical"));
param.add("value", new JsonPrimitive("80"));
param.add("type", new JsonPrimitive("PERCENT"));
param.add("description", new JsonPrimitive("The percent of disk space consumed before a critical alert is triggered."));
param.add("units", new JsonPrimitive("%"));
param.add("threshold", new JsonPrimitive("CRITICAL"));
paramsToAdd.add(param);
}
if (params.contains("request.by.status.warning.threshold")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("request.by.status.warning.threshold"));
param.add("display_name", new JsonPrimitive("Warning Request Time"));
param.add("value", new JsonPrimitive("3000"));
param.add("type", new JsonPrimitive("NUMERIC"));
param.add("description", new JsonPrimitive("The time to find requests in progress before a warning alert is triggered."));
param.add("units", new JsonPrimitive("ms"));
param.add("threshold", new JsonPrimitive("WARNING"));
paramsToAdd.add(param);
}
if (params.contains("request.by.status.critical.threshold")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("request.by.status.critical.threshold"));
param.add("display_name", new JsonPrimitive("Critical Request Time"));
param.add("value", new JsonPrimitive("5000"));
param.add("type", new JsonPrimitive("NUMERIC"));
param.add("description", new JsonPrimitive("The time to find requests in progress before a critical alert is triggered."));
param.add("units", new JsonPrimitive("ms"));
param.add("threshold", new JsonPrimitive("CRITICAL"));
paramsToAdd.add(param);
}
if (params.contains("task.status.aggregation.warning.threshold")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("task.status.aggregation.warning.threshold"));
param.add("display_name", new JsonPrimitive("Warning Process Time"));
param.add("value", new JsonPrimitive("3000"));
param.add("type", new JsonPrimitive("NUMERIC"));
param.add("description", new JsonPrimitive("The time to calculate a request's status from its tasks before a warning alert is triggered."));
param.add("units", new JsonPrimitive("ms"));
param.add("threshold", new JsonPrimitive("WARNING"));
paramsToAdd.add(param);
}
if (params.contains("task.status.aggregation.critical.threshold")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("task.status.aggregation.critical.threshold"));
param.add("display_name", new JsonPrimitive("Critical Process Time"));
param.add("value", new JsonPrimitive("5000"));
param.add("type", new JsonPrimitive("NUMERIC"));
param.add("description", new JsonPrimitive("The time to calculate a request's status from its tasks before a critical alert is triggered."));
param.add("units", new JsonPrimitive("ms"));
param.add("threshold", new JsonPrimitive("CRITICAL"));
paramsToAdd.add(param);
}
if (params.contains("rest.api.cluster.warning.threshold")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("rest.api.cluster.warning.threshold"));
param.add("display_name", new JsonPrimitive("Warning Response Time"));
param.add("value", new JsonPrimitive("5000"));
param.add("type", new JsonPrimitive("NUMERIC"));
param.add("description", new JsonPrimitive("The time to get a cluster via the REST API before a warning alert is triggered."));
param.add("units", new JsonPrimitive("ms"));
param.add("threshold", new JsonPrimitive("WARNING"));
paramsToAdd.add(param);
}
if (params.contains("rest.api.cluster.critical.threshold")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("rest.api.cluster.critical.threshold"));
param.add("display_name", new JsonPrimitive("Critical Response Time"));
param.add("value", new JsonPrimitive("7000"));
param.add("type", new JsonPrimitive("NUMERIC"));
param.add("description", new JsonPrimitive("The time to get a cluster via the REST API before a critical alert is triggered."));
param.add("units", new JsonPrimitive("ms"));
param.add("threshold", new JsonPrimitive("CRITICAL"));
paramsToAdd.add(param);
}
if (params.contains("socket.command")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("socket.command"));
param.add("display_name", new JsonPrimitive("Socket Command"));
param.add("value", new JsonPrimitive("ruok"));
param.add("type", new JsonPrimitive("STRING"));
param.add("description", new JsonPrimitive("A socket command which queries ZooKeeper to respond with its state. The expected response is imok."));
paramsToAdd.add(param);
}
if (params.contains("socket.command.response")) {
JsonObject param = new JsonObject();
param.add("name", new JsonPrimitive("socket.command.response"));
param.add("display_name", new JsonPrimitive("Expected Response"));
param.add("value", new JsonPrimitive("imok"));
param.add("type", new JsonPrimitive("STRING"));
param.add("description", new JsonPrimitive("The expected response to the socket command."));
paramsToAdd.add(param);
}
if (!parameterExists) {
parametersJson = new JsonArray();
for (JsonObject param : paramsToAdd) {
parametersJson.add(param);
}
sourceJson.add("parameters", parametersJson);
} else {
for (JsonObject param : paramsToAdd) {
parametersJson.add(param);
}
sourceJson.remove("parameters");
sourceJson.add("parameters", parametersJson);
}
return sourceJson.toString();
}
protected void updateAdminPermissionTable() throws SQLException {
// Add the sort_order column to the adminpermission table
dbAccessor.addColumn(ADMIN_PERMISSION_TABLE,
new DBColumnInfo(SORT_ORDER_COL, Short.class, null, 1, false));
// Add the principal_id column to the adminpermission table
// Note: This is set to nullable here, but will be altered once the column has been set
// properly during the DML update phase.
dbAccessor.addColumn(ADMIN_PERMISSION_TABLE,
new DBColumnInfo(PRINCIPAL_ID_COL, Long.class, null, null, true));
}
protected void updateTopologyRequestTable() throws SQLException {
// Add the sort_order column to the adminpermission table
dbAccessor.addColumn(TOPOLOGY_REQUEST_TABLE,
new DBColumnInfo(PROVISION_ACTION_COL, String.class, 255, null, true));
}
/**
* Updates the {@value #ALERT_DEFINITION_TABLE} in the following ways:
* <ul>
* <li>Craetes the {@value #HELP_URL_COLUMN} column</li>
* <li>Craetes the {@value #REPEAT_TOLERANCE_COLUMN} column</li>
* <li>Craetes the {@value #REPEAT_TOLERANCE_ENABLED_COLUMN} column</li>
* </ul>
*
* @throws SQLException
*/
protected void updateAlertDefinitionTable() throws SQLException {
dbAccessor.addColumn(ALERT_DEFINITION_TABLE,
new DBColumnInfo(HELP_URL_COLUMN, String.class, 512, null, true));
dbAccessor.addColumn(ALERT_DEFINITION_TABLE,
new DBColumnInfo(REPEAT_TOLERANCE_COLUMN, Integer.class, null, 1, false));
dbAccessor.addColumn(ALERT_DEFINITION_TABLE,
new DBColumnInfo(REPEAT_TOLERANCE_ENABLED_COLUMN, Short.class, null, 0, false));
}
/**
* Updates the {@value #ALERT_CURRENT_TABLE} in the following ways:
* <ul>
* <li>Creates the {@value #ALERT_CURRENT_OCCURRENCES_COLUMN} column</li>
* <li>Creates the {@value #ALERT_CURRENT_FIRMNESS_COLUMN} column</li>
* </ul>
*
* @throws SQLException
*/
protected void updateAlertCurrentTable() throws SQLException {
dbAccessor.addColumn(ALERT_CURRENT_TABLE,
new DBColumnInfo(ALERT_CURRENT_OCCURRENCES_COLUMN, Long.class, null, 1, false));
dbAccessor.addColumn(ALERT_CURRENT_TABLE, new DBColumnInfo(ALERT_CURRENT_FIRMNESS_COLUMN,
String.class, 255, AlertFirmness.HARD.name(), false));
}
/**
* Updates the {@value #ALERT_TARGET_TABLE} in the following ways:
* <ul>
* <li>Creates the {@value #ALERT_TARGET_ENABLED_COLUMN} column</li>
* </ul>
*
* @throws SQLException
*/
protected void updateAlertTargetTable() throws SQLException {
dbAccessor.addColumn(ALERT_TARGET_TABLE,
new DBColumnInfo(ALERT_TARGET_ENABLED_COLUMN, Short.class, null, 1, false));
}
protected void setRoleSortOrder() throws SQLException {
String updateStatement = "UPDATE " + ADMIN_PERMISSION_TABLE + " SET " + SORT_ORDER_COL + "=%d WHERE " + PERMISSION_ID_COL + "='%s'";
LOG.info("Setting permission labels");
dbAccessor.executeUpdate(String.format(updateStatement,
1, PermissionEntity.AMBARI_ADMINISTRATOR_PERMISSION_NAME));
dbAccessor.executeUpdate(String.format(updateStatement,
2, PermissionEntity.CLUSTER_ADMINISTRATOR_PERMISSION_NAME));
dbAccessor.executeUpdate(String.format(updateStatement,
3, PermissionEntity.CLUSTER_OPERATOR_PERMISSION_NAME));
dbAccessor.executeUpdate(String.format(updateStatement,
4, PermissionEntity.SERVICE_ADMINISTRATOR_PERMISSION_NAME));
dbAccessor.executeUpdate(String.format(updateStatement,
5, PermissionEntity.SERVICE_OPERATOR_PERMISSION_NAME));
dbAccessor.executeUpdate(String.format(updateStatement,
6, PermissionEntity.CLUSTER_USER_PERMISSION_NAME));
dbAccessor.executeUpdate(String.format(updateStatement,
7, PermissionEntity.VIEW_USER_PERMISSION_NAME));
}
/**
* Create and update records to create the role-based principals.
* <p>
* This includes creating the new "ROLE" principal type, a principal for each role, and finally
* updating the princial_id column for the role.
*/
void createRolePrincipals() throws SQLException {
// Create Role Principal Type
PrincipalTypeEntity rolePrincipalType = new PrincipalTypeEntity();
rolePrincipalType.setName("ROLE");
// creates the new record and returns an entity with the id set.
rolePrincipalType = principalTypeDAO.merge(rolePrincipalType);
// Get the roles (adminpermissions) and create a principal for each.... set the role's principal_id
// value as we go...
List<PermissionEntity> roleEntities = permissionDAO.findAll();
for (PermissionEntity roleEntity : roleEntities) {
PrincipalEntity principalEntity = new PrincipalEntity();
principalEntity.setPrincipalType(rolePrincipalType);
roleEntity.setPrincipal(principalDAO.merge(principalEntity));
permissionDAO.merge(roleEntity);
}
// Fix the adminpermission.principal_id column to be non-nullable:
dbAccessor.alterColumn(ADMIN_PERMISSION_TABLE,
new DBColumnInfo(PRINCIPAL_ID_COL, Long.class, null, null, false));
}
/**
* Makes the following changes to the {@value #REPO_VERSION_TABLE} table:
* <ul>
* <li>repo_type VARCHAR(255) DEFAULT 'STANDARD' NOT NULL</li>
* <li>version_url VARCHAR(1024)</li>
* <li>version_xml MEDIUMTEXT</li>
* <li>version_xsd VARCHAR(512)</li>
* <li>parent_id BIGINT</li>
* </ul>
*
* @throws SQLException
*/
private void updateRepoVersionTableDDL() throws SQLException {
DBColumnInfo repoTypeColumn = new DBColumnInfo("repo_type", String.class, 255, RepositoryType.STANDARD.name(), false);
DBColumnInfo versionUrlColumn = new DBColumnInfo("version_url", String.class, 1024, null, true);
DBColumnInfo versionXmlColumn = new DBColumnInfo("version_xml", Clob.class, null, null, true);
DBColumnInfo versionXsdColumn = new DBColumnInfo("version_xsd", String.class, 512, null, true);
DBColumnInfo parentIdColumn = new DBColumnInfo("parent_id", Long.class, null, null, true);
dbAccessor.addColumn(REPO_VERSION_TABLE, repoTypeColumn);
dbAccessor.addColumn(REPO_VERSION_TABLE, versionUrlColumn);
dbAccessor.addColumn(REPO_VERSION_TABLE, versionXmlColumn);
dbAccessor.addColumn(REPO_VERSION_TABLE, versionXsdColumn);
dbAccessor.addColumn(REPO_VERSION_TABLE, parentIdColumn);
}
/**
* Makes the following changes to the {@value #SERVICE_COMPONENT_DS_TABLE} table,
* but only if the table doesn't have it's new PK set.
* <ul>
* <li>id BIGINT NOT NULL</li>
* <li>Drops FKs on {@value #HOST_COMPONENT_DS_TABLE} and {@value #HOST_COMPONENT_STATE_TABLE}</li>
* <li>Populates ID in {@value #SERVICE_COMPONENT_DS_TABLE}</li>
* <li>Creates {@code UNIQUE} constraint on {@value #HOST_COMPONENT_DS_TABLE}</li>
* <li>Adds FKs on {@value #HOST_COMPONENT_DS_TABLE} and {@value #HOST_COMPONENT_STATE_TABLE}</li>
* <li>Adds new sequence value of {@code servicecomponentdesiredstate_id_seq}</li>
* </ul>
*
* @throws SQLException
*/
@Transactional
private void updateServiceComponentDesiredStateTableDDL() throws SQLException {
if (dbAccessor.tableHasPrimaryKey(SERVICE_COMPONENT_DS_TABLE, ID)) {
LOG.info("Skipping {} table Primary Key modifications since the new {} column already exists",
SERVICE_COMPONENT_DS_TABLE, ID);
return;
}
// drop FKs to SCDS in both HCDS and HCS tables
// These are the expected constraint names
dbAccessor.dropFKConstraint(HOST_COMPONENT_DS_TABLE, "hstcmpnntdesiredstatecmpnntnme");
dbAccessor.dropFKConstraint(HOST_COMPONENT_STATE_TABLE, "hstcomponentstatecomponentname");
// These are the old (pre Ambari 1.5) constraint names, however still found on some installations
dbAccessor.dropFKConstraint(HOST_COMPONENT_DS_TABLE, "FK_hostcomponentdesiredstate_component_name");
dbAccessor.dropFKConstraint(HOST_COMPONENT_STATE_TABLE, "FK_hostcomponentstate_component_name");
// remove existing compound PK
dbAccessor.dropPKConstraint(SERVICE_COMPONENT_DS_TABLE, "servicecomponentdesiredstate_pkey");
// add new PK column to SCDS, making it nullable for now
DBColumnInfo idColumn = new DBColumnInfo(ID, Long.class, null, null, true);
dbAccessor.addColumn(SERVICE_COMPONENT_DS_TABLE, idColumn);
// populate SCDS id column
AtomicLong scdsIdCounter = new AtomicLong(1);
Statement statement = null;
ResultSet resultSet = null;
try {
statement = dbAccessor.getConnection().createStatement();
if (statement != null) {
String selectSQL = String.format("SELECT cluster_id, service_name, component_name FROM %s",
SERVICE_COMPONENT_DS_TABLE);
resultSet = statement.executeQuery(selectSQL);
while (null != resultSet && resultSet.next()) {
final Long clusterId = resultSet.getLong("cluster_id");
final String serviceName = resultSet.getString("service_name");
final String componentName = resultSet.getString("component_name");
String updateSQL = String.format(
"UPDATE %s SET %s = %d WHERE cluster_id = %d AND service_name = '%s' AND component_name = '%s'",
SERVICE_COMPONENT_DS_TABLE, ID, scdsIdCounter.getAndIncrement(), clusterId,
serviceName, componentName);
dbAccessor.executeQuery(updateSQL);
}
}
} finally {
JdbcUtils.closeResultSet(resultSet);
JdbcUtils.closeStatement(statement);
}
// make the column NON NULL now
dbAccessor.alterColumn(SERVICE_COMPONENT_DS_TABLE,
new DBColumnInfo(ID, Long.class, null, null, false));
// create a new PK, matching the name of the constraint found in SQL
dbAccessor.addPKConstraint(SERVICE_COMPONENT_DS_TABLE, "pk_sc_desiredstate", ID);
// create UNIQUE constraint, ensuring column order matches SQL files
String[] uniqueColumns = new String[] { "component_name", "service_name", "cluster_id" };
dbAccessor.addUniqueConstraint(SERVICE_COMPONENT_DS_TABLE, "UQ_scdesiredstate_name",
uniqueColumns);
// add FKs back to SCDS in both HCDS and HCS tables
dbAccessor.addFKConstraint(HOST_COMPONENT_DS_TABLE, "hstcmpnntdesiredstatecmpnntnme",
uniqueColumns, SERVICE_COMPONENT_DS_TABLE, uniqueColumns, false);
dbAccessor.addFKConstraint(HOST_COMPONENT_STATE_TABLE, "hstcomponentstatecomponentname",
uniqueColumns, SERVICE_COMPONENT_DS_TABLE, uniqueColumns, false);
// Add sequence for SCDS id
addSequence("servicecomponentdesiredstate_id_seq", scdsIdCounter.get(), false);
}
/**
* Makes the following changes to the {@value #SERVICE_COMPONENT_HISTORY_TABLE} table:
* <ul>
* <li>id BIGINT NOT NULL</li>
* <li>component_id BIGINT NOT NULL</li>
* <li>upgrade_id BIGINT NOT NULL</li>
* <li>from_stack_id BIGINT NOT NULL</li>
* <li>to_stack_id BIGINT NOT NULL</li>
* <li>CONSTRAINT PK_sc_history PRIMARY KEY (id)</li>
* <li>CONSTRAINT FK_sc_history_component_id FOREIGN KEY (component_id) REFERENCES servicecomponentdesiredstate (id)</li>
* <li>CONSTRAINT FK_sc_history_upgrade_id FOREIGN KEY (upgrade_id) REFERENCES upgrade (upgrade_id)</li>
* <li>CONSTRAINT FK_sc_history_from_stack_id FOREIGN KEY (from_stack_id) REFERENCES stack (stack_id)</li>
* <li>CONSTRAINT FK_sc_history_to_stack_id FOREIGN KEY (to_stack_id) REFERENCES stack (stack_id)</li>
* <li>Creates the {@code servicecomponent_history_id_seq}</li>
* </ul>
*
* @throws SQLException
*/
private void createServiceComponentHistoryTable() throws SQLException {
List<DBColumnInfo> columns = new ArrayList<>();
columns.add(new DBColumnInfo(ID, Long.class, null, null, false));
columns.add(new DBColumnInfo("component_id", Long.class, null, null, false));
columns.add(new DBColumnInfo("upgrade_id", Long.class, null, null, false));
columns.add(new DBColumnInfo("from_stack_id", Long.class, null, null, false));
columns.add(new DBColumnInfo("to_stack_id", Long.class, null, null, false));
dbAccessor.createTable(SERVICE_COMPONENT_HISTORY_TABLE, columns, (String[]) null);
dbAccessor.addPKConstraint(SERVICE_COMPONENT_HISTORY_TABLE, "PK_sc_history", ID);
dbAccessor.addFKConstraint(SERVICE_COMPONENT_HISTORY_TABLE, "FK_sc_history_component_id",
"component_id", SERVICE_COMPONENT_DS_TABLE, "id", false);
dbAccessor.addFKConstraint(SERVICE_COMPONENT_HISTORY_TABLE, "FK_sc_history_upgrade_id",
"upgrade_id", UPGRADE_TABLE, "upgrade_id", false);
dbAccessor.addFKConstraint(SERVICE_COMPONENT_HISTORY_TABLE, "FK_sc_history_from_stack_id",
"from_stack_id", STACK_TABLE, "stack_id", false);
dbAccessor.addFKConstraint(SERVICE_COMPONENT_HISTORY_TABLE, "FK_sc_history_to_stack_id",
"to_stack_id", STACK_TABLE, "stack_id", false);
addSequence("servicecomponent_history_id_seq", 0L, false);
}
/**
* Alter servicecomponentdesiredstate table to add recovery_enabled column.
* @throws SQLException
*/
private void updateServiceComponentDesiredStateTable() throws SQLException {
// ALTER TABLE servicecomponentdesiredstate ADD COLUMN
// recovery_enabled SMALLINT DEFAULT 0 NOT NULL
dbAccessor.addColumn(SERVICE_COMPONENT_DESIRED_STATE_TABLE,
new DBColumnInfo(RECOVERY_ENABLED_COL, Short.class, null, 0, false));
dbAccessor.addColumn(SERVICE_COMPONENT_DESIRED_STATE_TABLE,
new DBColumnInfo(DESIRED_VERSION_COLUMN_NAME, String.class, 255, State.UNKNOWN.toString(), false));
}
/**
* Alter host_role_command table to add original_start_time, which is needed because the start_time column now
* allows overriding the value in ActionScheduler.java
* @throws SQLException
*/
private void updateHostRoleCommandTableDDL() throws SQLException {
final String columnName = "original_start_time";
DBColumnInfo originalStartTimeColumn = new DBColumnInfo(columnName, Long.class, null, -1L, true);
dbAccessor.addColumn(HOST_ROLE_COMMAND_TABLE, originalStartTimeColumn);
}
/**
* Alter host_role_command table to update original_start_time with values and make it non-nullable
* @throws SQLException
*/
protected void updateHostRoleCommandTableDML() throws SQLException {
final String columnName = "original_start_time";
dbAccessor.executeQuery("UPDATE " + HOST_ROLE_COMMAND_TABLE + " SET original_start_time = start_time", false);
dbAccessor.executeQuery("UPDATE " + HOST_ROLE_COMMAND_TABLE + " SET original_start_time=-1 WHERE original_start_time IS NULL");
dbAccessor.setColumnNullable(HOST_ROLE_COMMAND_TABLE, columnName, false);
}
/**
* Puts each item in the specified list inside single quotes and
* returns a comma separated value for use in a SQL query.
* @param list
* @return
*/
private String sqlStringListFromArrayList(List<String> list) {
List sqlList = new ArrayList<String>(list.size());
for (String item : list) {
sqlList.add(String.format("'%s'", item.trim()));
}
return StringUtils.join(sqlList, ',');
}
/**
* Update clusterconfig table for config type 'cluster-env' with the
* recovery attributes.
*
* @throws AmbariException
*/
private void updateRecoveryClusterEnvConfig() throws AmbariException {
Map<String, String> propertyMap = new HashMap<>();
if (StringUtils.isNotEmpty(config.getNodeRecoveryType())) {
propertyMap.put(RecoveryConfigHelper.RECOVERY_ENABLED_KEY, "true");
propertyMap.put(RecoveryConfigHelper.RECOVERY_TYPE_KEY, config.getNodeRecoveryType());
}
else {
propertyMap.put(RecoveryConfigHelper.RECOVERY_ENABLED_KEY, "false");
}
if (StringUtils.isNotEmpty(config.getNodeRecoveryLifetimeMaxCount())) {
propertyMap.put(RecoveryConfigHelper.RECOVERY_LIFETIME_MAX_COUNT_KEY, config.getNodeRecoveryLifetimeMaxCount());
}
if (StringUtils.isNotEmpty(config.getNodeRecoveryMaxCount())) {
propertyMap.put(RecoveryConfigHelper.RECOVERY_MAX_COUNT_KEY, config.getNodeRecoveryMaxCount());
}
if (StringUtils.isNotEmpty(config.getNodeRecoveryRetryGap())) {
propertyMap.put(RecoveryConfigHelper.RECOVERY_RETRY_GAP_KEY, config.getNodeRecoveryRetryGap());
}
if (StringUtils.isNotEmpty(config.getNodeRecoveryWindowInMin())) {
propertyMap.put(RecoveryConfigHelper.RECOVERY_WINDOW_IN_MIN_KEY, config.getNodeRecoveryWindowInMin());
}
AmbariManagementController ambariManagementController = injector.getInstance(
AmbariManagementController.class);
Clusters clusters = ambariManagementController.getClusters();
// for each cluster, update/create the cluster-env config type in clusterconfig
Map<String, Cluster> clusterMap = getCheckedClusterMap(clusters);
for (final Cluster cluster : clusterMap.values()) {
updateConfigurationPropertiesForCluster(cluster, ConfigHelper.CLUSTER_ENV, propertyMap,
true /* update if exists */, true /* create new config type */);
}
}
/**
* Alter servicecomponentdesiredstate table to update recovery_enabled to 1
* for the components that have been marked for auto start in ambari.properties
* @throws SQLException
*/
private void updateRecoveryComponents() throws SQLException {
/*
* Whether specific components are enabled/disabled for recovery. Being enabled takes
* precedence over being disabled. When specific components are enabled then only
* those components are enabled. When specific components are disabled then all of
* the other components are enabled.
*/
String enabledComponents = config.getRecoveryEnabledComponents();
String disabledComponents = config.getRecoveryDisabledComponents();
String query;
if (StringUtils.isEmpty(enabledComponents)) {
if (StringUtils.isEmpty(disabledComponents)) {
// disable all components
query = String.format("UPDATE %s SET recovery_enabled = 0", SERVICE_COMPONENT_DESIRED_STATE_TABLE);
}
else {
// enable (1 - disabledComponents)
List<String> disabledComponentsList = Arrays.asList(disabledComponents.split(","));
String components = sqlStringListFromArrayList(disabledComponentsList);
query = String.format("UPDATE %s SET recovery_enabled = 1 WHERE component_name NOT IN (%s)",
SERVICE_COMPONENT_DESIRED_STATE_TABLE, components);
}
}
else {
// enable the specified components
List<String> enabledComponentsList = Arrays.asList(enabledComponents.split(","));
String components = sqlStringListFromArrayList(enabledComponentsList);
query = String.format("UPDATE %s SET recovery_enabled = 1 WHERE component_name IN (%s)",
SERVICE_COMPONENT_DESIRED_STATE_TABLE, components);
}
dbAccessor.executeQuery(query);
}
/**
* Update clusterconfig table and servicecomponentdesiredstate table with the
* recovery attributes and componenents to be recovered.
*
* @throws SQLException
*/
@Transactional
protected void updateRecoveryConfigurationDML() throws SQLException, AmbariException {
updateRecoveryClusterEnvConfig();
updateRecoveryComponents();
}
/**
* Update Clusters and Hosts Version State from UPGRADING, UPGRADE_FAILED to INSTALLED
* and UPGRADED to CURRENT if repo_version_id from cluster_version equals repo_version_id of Clusters and Hosts Version State
*
* @throws SQLException
*/
@Transactional
protected void updateClustersAndHostsVersionStateTableDML() throws SQLException, AmbariException {
dbAccessor.executeQuery("UPDATE " + HOST_VERSION_TABLE + " SET state = 'INSTALLED' WHERE state IN ('UPGRADING', 'UPGRADE_FAILED', 'UPGRADED')");
dbAccessor.executeQuery("UPDATE " + CLUSTER_VERSION_TABLE + " SET state = 'INSTALLED' WHERE state IN ('UPGRADING', 'UPGRADE_FAILED', 'UPGRADED')");
Statement statement = null;
ResultSet resultSet = null;
try {
statement = dbAccessor.getConnection().createStatement();
if (statement != null) {
String selectSQL = String.format("SELECT repo_version_id, cluster_id FROM %s WHERE state = 'CURRENT'",
CLUSTER_VERSION_TABLE);
resultSet = statement.executeQuery(selectSQL);
Set<Long> clusterIds = new HashSet<>();
while (null != resultSet && resultSet.next()) {
Long clusterId = resultSet.getLong("cluster_id");
if (clusterIds.contains(clusterId)) {
throw new AmbariException(String.format("Database is in a bad state. Cluster %s contains multiple CURRENT version", clusterId));
}
clusterIds.add(clusterId);
Long repoVersionId = resultSet.getLong("repo_version_id");
String updateHostVersionSQL = String.format(
"UPDATE %s SET state = 'CURRENT' WHERE repo_version_id = %s", HOST_VERSION_TABLE, repoVersionId);
String updateClusterVersionSQL = String.format(
"UPDATE %s SET state = 'CURRENT' WHERE repo_version_id = %s", CLUSTER_VERSION_TABLE, repoVersionId);
dbAccessor.executeQuery(updateHostVersionSQL);
dbAccessor.executeQuery(updateClusterVersionSQL);
}
}
} finally {
JdbcUtils.closeResultSet(resultSet);
JdbcUtils.closeStatement(statement);
}
}
/**
* In hdfs-site, set dfs.client.retry.policy.enabled=false
* This is needed for Rolling/Express upgrade so that clients don't keep retrying, which exhausts the retries and
* doesn't allow for a graceful failover, which is expected.
*
* Rely on dfs.internal.nameservices after upgrade. Copy the value from dfs.services
* @throws AmbariException
*/
protected void updateHDFSConfigs() throws AmbariException {
AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
Clusters clusters = ambariManagementController.getClusters();
if (clusters != null) {
Map<String, Cluster> clusterMap = clusters.getClusters();
if (clusterMap != null && !clusterMap.isEmpty()) {
for (final Cluster cluster : clusterMap.values()) {
Set<String> installedServices = cluster.getServices().keySet();
if (installedServices.contains("HDFS")) {
Config hdfsSite = cluster.getDesiredConfigByType("hdfs-site");
if (hdfsSite != null) {
String clientRetryPolicyEnabled = hdfsSite.getProperties().get("dfs.client.retry.policy.enabled");
if (null != clientRetryPolicyEnabled && Boolean.parseBoolean(clientRetryPolicyEnabled)) {
updateConfigurationProperties("hdfs-site", Collections.singletonMap("dfs.client.retry.policy.enabled", "false"), true, false);
}
String nameservices = hdfsSite.getProperties().get("dfs.nameservices");
String int_nameservices = hdfsSite.getProperties().get("dfs.internal.nameservices");
if(int_nameservices == null && nameservices != null) {
updateConfigurationProperties("hdfs-site", Collections.singletonMap("dfs.internal.nameservices", nameservices), true, false);
}
}
Config hadoopEnv = cluster.getDesiredConfigByType("hadoop-env");
if (hadoopEnv != null) {
String keyServerPort = hadoopEnv.getProperties().get("keyserver_port");
if (null != keyServerPort && " ".equals(keyServerPort)) {
updateConfigurationProperties("hadoop-env", Collections.singletonMap("keyserver_port", ""), true, false);
}
}
}
}
}
}
}
protected void updateHIVEConfigs() throws AmbariException {
AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
Clusters clusters = ambariManagementController.getClusters();
if (clusters != null) {
Map<String, Cluster> clusterMap = clusters.getClusters();
if (clusterMap != null && !clusterMap.isEmpty()) {
for (final Cluster cluster : clusterMap.values()) {
Set<String> installedServices = cluster.getServices().keySet();
if (installedServices.contains("HIVE")) {
Config hiveSite = cluster.getDesiredConfigByType("hive-site");
if (hiveSite != null) {
Map<String, String> hiveSiteProperties = hiveSite.getProperties();
String txn_manager = hiveSiteProperties.get("hive.txn.manager");
String concurrency = hiveSiteProperties.get("hive.support.concurrency");
String initiator_on = hiveSiteProperties.get("hive.compactor.initiator.on");
String partition_mode = hiveSiteProperties.get("hive.exec.dynamic.partition.mode");
boolean acid_enabled =
txn_manager != null && txn_manager.equals("org.apache.hadoop.hive.ql.lockmgr.DbTxnManager") &&
concurrency != null && concurrency.toLowerCase().equals("true") &&
initiator_on != null && initiator_on.toLowerCase().equals("true") &&
partition_mode != null && partition_mode.equals("nonstrict");
Config hiveEnv = cluster.getDesiredConfigByType("hive-env");
if(hiveEnv != null){
if(acid_enabled) {
updateConfigurationProperties("hive-env", Collections.singletonMap("hive_txn_acid", "on"), true, false);
}
}
}
}
}
}
}
}
protected void updateAMSConfigs() throws AmbariException {
AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
Clusters clusters = ambariManagementController.getClusters();
if (clusters != null) {
Map<String, Cluster> clusterMap = clusters.getClusters();
if (clusterMap != null && !clusterMap.isEmpty()) {
for (final Cluster cluster : clusterMap.values()) {
Config amsEnv = cluster.getDesiredConfigByType("ams-env");
if (amsEnv != null) {
String content = amsEnv.getProperties().get("content");
if (content != null && !content.contains("AMS_INSTANCE_NAME")) {
String newContent = content + "\n # AMS instance name\n" +
"export AMS_INSTANCE_NAME={{hostname}}\n";
updateConfigurationProperties("ams-env", Collections.singletonMap("content", newContent), true, true);
}
}
Config amsHBaseEnv = cluster.getDesiredConfigByType("ams-hbase-env");
if (amsHBaseEnv != null) {
String content = amsHBaseEnv.getProperties().get("content");
Map<String, String> newProperties = new HashMap<>();
if (content != null && !content.contains("HBASE_HOME=")) {
String newContent = content + "\n # Explicitly Setting HBASE_HOME for AMS HBase so that there is no conflict\n" +
"export HBASE_HOME={{ams_hbase_home_dir}}\n";
newProperties.put("content", newContent);
}
updateConfigurationPropertiesForCluster(cluster, "ams-hbase-env", newProperties, true, true);
}
Config amsSite = cluster.getDesiredConfigByType(AMS_SITE);
if (amsSite != null) {
String metadataFilters = amsSite.getProperties().get("timeline.metrics.service.metadata.filters");
if (StringUtils.isEmpty(metadataFilters) ||
!metadataFilters.contains("ContainerResource")) {
updateConfigurationProperties("ams-site",
Collections.singletonMap("timeline.metrics.service.metadata.filters", "ContainerResource"), true, false);
}
Map<String, String> amsSiteProperties = amsSite.getProperties();
Map<String, String> newProperties = new HashMap<>();
if (!amsSiteProperties.containsKey(TIMELINE_METRICS_SINK_COLLECTION_PERIOD) ||
"60".equals(amsSiteProperties.get(TIMELINE_METRICS_SINK_COLLECTION_PERIOD))) {
newProperties.put(TIMELINE_METRICS_SINK_COLLECTION_PERIOD, "10");
LOG.info("Setting value of " + TIMELINE_METRICS_SINK_COLLECTION_PERIOD + " : 10");
}
updateConfigurationPropertiesForCluster(cluster, AMS_SITE, newProperties, true, true);
}
Config amsGrafanaIni = cluster.getDesiredConfigByType("ams-grafana-ini");
if (amsGrafanaIni != null) {
Map<String, String> amsGrafanaIniProperties = amsGrafanaIni.getProperties();
String content = amsGrafanaIniProperties.get("content");
Map<String, String> newProperties = new HashMap<>();
newProperties.put("content", updateAmsGrafanaIni(content));
updateConfigurationPropertiesForCluster(cluster, "ams-grafana-ini", newProperties, true, true);
}
Config amsHbaseSite = cluster.getDesiredConfigByType(AMS_HBASE_SITE);
if (amsHbaseSite != null) {
Map<String, String> amsHbaseSiteProperties = amsHbaseSite.getProperties();
Map<String, String> newProperties = new HashMap<>();
if (amsHbaseSiteProperties.containsKey(HBASE_RPC_TIMEOUT_PROPERTY) &&
"30000".equals(amsHbaseSiteProperties.get(HBASE_RPC_TIMEOUT_PROPERTY))) {
newProperties.put(HBASE_RPC_TIMEOUT_PROPERTY, String.valueOf(300000));
}
if(amsHbaseSiteProperties.containsKey(AMS_HBASE_SITE_NORMALIZER_ENABLED_PROPERTY) &&
"true".equals(amsHbaseSiteProperties.get(AMS_HBASE_SITE_NORMALIZER_ENABLED_PROPERTY))) {
LOG.info("Disabling " + AMS_HBASE_SITE_NORMALIZER_ENABLED_PROPERTY);
newProperties.put(AMS_HBASE_SITE_NORMALIZER_ENABLED_PROPERTY, String.valueOf(false));
}
updateConfigurationPropertiesForCluster(cluster, AMS_HBASE_SITE, newProperties, true, true);
}
}
}
}
}
protected String updateAmsGrafanaIni(String content) {
if (content == null) {
return null;
}
String regSearch = "/var/lib/ambari-metrics-grafana";
String replacement = "{{ams_grafana_data_dir}}";
content = content.replaceAll(regSearch, replacement);
return content;
}
/**
* Create blueprint_setting table for storing the "settings" section
* in the blueprint. Auto start information is specified in the "settings" section.
*
* @throws SQLException
*/
private void createBlueprintSettingTable() throws SQLException {
List<DBColumnInfo> columns = new ArrayList<>();
// Add blueprint_setting table
LOG.info("Creating " + BLUEPRINT_SETTING_TABLE + " table");
columns.add(new DBColumnInfo(ID, Long.class, null, null, false));
columns.add(new DBColumnInfo(BLUEPRINT_NAME_COL, String.class, 255, null, false));
columns.add(new DBColumnInfo(SETTING_NAME_COL, String.class, 255, null, false));
columns.add(new DBColumnInfo(SETTING_DATA_COL, char[].class, null, null, false));
dbAccessor.createTable(BLUEPRINT_SETTING_TABLE, columns);
dbAccessor.addPKConstraint(BLUEPRINT_SETTING_TABLE, "PK_blueprint_setting", ID);
dbAccessor.addUniqueConstraint(BLUEPRINT_SETTING_TABLE, "UQ_blueprint_setting_name", BLUEPRINT_NAME_COL, SETTING_NAME_COL);
dbAccessor.addFKConstraint(BLUEPRINT_SETTING_TABLE, "FK_blueprint_setting_name",
BLUEPRINT_NAME_COL, BLUEPRINT_TABLE, BLUEPRINT_NAME_COL, false);
addSequence("blueprint_setting_id_seq", 0L, false);
}
/**
* Updates {@code cluster-env} in the following ways:
* <ul>
* <li>Adds {@link ConfigHelper#CLUSTER_ENV_ALERT_REPEAT_TOLERANCE} = 1</li>
* <li>Adds {@link UpgradeCatalog240#ONE_DIR_PER_PARITION_PROPERTY} = false</li>
* </ul>
*
* @throws Exception
*/
protected void updateClusterEnv() throws AmbariException {
Map<String, String> propertyMap = new HashMap<>();
propertyMap.put(ConfigHelper.CLUSTER_ENV_ALERT_REPEAT_TOLERANCE, "1");
propertyMap.put(ONE_DIR_PER_PARITION_PROPERTY, "false");
AmbariManagementController ambariManagementController = injector.getInstance(
AmbariManagementController.class);
Clusters clusters = ambariManagementController.getClusters();
Map<String, Cluster> clusterMap = getCheckedClusterMap(clusters);
for (final Cluster cluster : clusterMap.values()) {
updateConfigurationPropertiesForCluster(cluster, ConfigHelper.CLUSTER_ENV, propertyMap, true,
true);
}
}
/**
* Updates {@code yarn-env} in the following ways:
* <ul>
* <li>Replays export YARN_HISTORYSERVER_HEAPSIZE={{apptimelineserver_heapsize}} to export
* YARN_TIMELINESERVER_HEAPSIZE={{apptimelineserver_heapsize}}</li>
* </ul>
*
* @throws Exception
*/
protected void updateYarnEnv() throws AmbariException {
AmbariManagementController ambariManagementController = injector.getInstance(
AmbariManagementController.class);
Clusters clusters = ambariManagementController.getClusters();
Map<String, Cluster> clusterMap = getCheckedClusterMap(clusters);
for (final Cluster cluster : clusterMap.values()) {
Config yarnEnvConfig = cluster.getDesiredConfigByType(YARN_ENV_CONFIG);
Map<String, String> yarnEnvProps = new HashMap<String, String>();
if (yarnEnvConfig != null) {
String content = yarnEnvConfig.getProperties().get("content");
// comment old property
content = content.replaceAll("export YARN_HISTORYSERVER_HEAPSIZE=\\{\\{apptimelineserver_heapsize\\}\\}",
"# export YARN_HISTORYSERVER_HEAPSIZE=\\{\\{apptimelineserver_heapsize\\}\\}");
// add new correct property
content = content + "\n\n # Specify the max Heapsize for the timeline server using a numerical value\n" +
" # in the scale of MB. For example, to specify an jvm option of -Xmx1000m, set\n" +
" # the value to 1024.\n" +
" # This value will be overridden by an Xmx setting specified in either YARN_OPTS\n" +
" # and/or YARN_TIMELINESERVER_OPTS.\n" +
" # If not specified, the default value will be picked from either YARN_HEAPMAX\n" +
" # or JAVA_HEAP_MAX with YARN_HEAPMAX as the preferred option of the two.\n" +
" export YARN_TIMELINESERVER_HEAPSIZE={{apptimelineserver_heapsize}}";
yarnEnvProps.put("content", content);
updateConfigurationPropertiesForCluster(cluster, YARN_ENV_CONFIG, yarnEnvProps, true, true);
}
}
}
/**
* Updates the Kerberos-related configurations for the clusters managed by this Ambari
* <p/>
* Performs the following updates:
* <ul>
* <li>Rename <code>kerberos-env/kdc_host</code> to
* <code>kerberos-env/kdc_hosts</li>
* <li>If krb5-conf/content was not changed from the original stack default, update it to the new
* stack default</li>
* </ul>
*
* @throws AmbariException if an error occurs while updating the configurations
*/
protected void updateKerberosConfigs() throws AmbariException {
AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
Clusters clusters = ambariManagementController.getClusters();
Map<String, Cluster> clusterMap = getCheckedClusterMap(clusters);
for (final Cluster cluster : clusterMap.values()) {
Config config;
config = cluster.getDesiredConfigByType("kerberos-env");
if (config != null) {
// Rename kdc_host to kdc_hosts
String value = config.getProperties().get("kdc_host");
Map<String, String> updates = Collections.singletonMap("kdc_hosts", value);
Set<String> removes = Collections.singleton("kdc_host");
updateConfigurationPropertiesForCluster(cluster, "kerberos-env", updates, removes, true, false);
}
config = cluster.getDesiredConfigByType("krb5-conf");
if (config != null) {
String value = config.getProperties().get("content");
String oldDefault = "\n[libdefaults]\n renew_lifetime \u003d 7d\n forwardable \u003d true\n default_realm \u003d {{realm}}\n ticket_lifetime \u003d 24h\n dns_lookup_realm \u003d false\n dns_lookup_kdc \u003d false\n #default_tgs_enctypes \u003d {{encryption_types}}\n #default_tkt_enctypes \u003d {{encryption_types}}\n\n{% if domains %}\n[domain_realm]\n{% for domain in domains.split(\u0027,\u0027) %}\n {{domain|trim}} \u003d {{realm}}\n{% endfor %}\n{% endif %}\n\n[logging]\n default \u003d FILE:/var/log/krb5kdc.log\n admin_server \u003d FILE:/var/log/kadmind.log\n kdc \u003d FILE:/var/log/krb5kdc.log\n\n[realms]\n {{realm}} \u003d {\n admin_server \u003d {{admin_server_host|default(kdc_host, True)}}\n kdc \u003d {{kdc_host}}\n }\n\n{# Append additional realm declarations below #}";
// if the content is the same as the old stack default, update to the new stack default;
// else leave it alone since the user may have changed it for a reason.
if(oldDefault.equalsIgnoreCase(value)) {
String newDefault ="[libdefaults]\n renew_lifetime = 7d\n forwardable = true\n default_realm = {{realm}}\n ticket_lifetime = 24h\n dns_lookup_realm = false\n dns_lookup_kdc = false\n #default_tgs_enctypes = {{encryption_types}}\n #default_tkt_enctypes = {{encryption_types}}\n{% if domains %}\n[domain_realm]\n{%- for domain in domains.split(',') %}\n {{domain|trim()}} = {{realm}}\n{%- endfor %}\n{% endif %}\n[logging]\n default = FILE:/var/log/krb5kdc.log\n admin_server = FILE:/var/log/kadmind.log\n kdc = FILE:/var/log/krb5kdc.log\n\n[realms]\n {{realm}} = {\n{%- if kdc_hosts > 0 -%}\n{%- set kdc_host_list = kdc_hosts.split(',') -%}\n{%- if kdc_host_list and kdc_host_list|length > 0 %}\n admin_server = {{admin_server_host|default(kdc_host_list[0]|trim(), True)}}\n{%- if kdc_host_list -%}\n{% for kdc_host in kdc_host_list %}\n kdc = {{kdc_host|trim()}}\n{%- endfor -%}\n{% endif %}\n{%- endif %}\n{%- endif %}\n }\n\n{# Append additional realm declarations below #}";
Map<String, String> updates = Collections.singletonMap("content", newDefault);
updateConfigurationPropertiesForCluster(cluster, "krb5-conf", updates, null, true, false);
}
}
}
}
/**
* Updates the Falcon-related configurations for the clusters managed by this Ambari
* Removes falcon_store_uri from falcon-env.
*
* @throws AmbariException if an error occurs while updating the configurations
*/
protected void updateFalconConfigs() throws AmbariException {
AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
Clusters clusters = ambariManagementController.getClusters();
Map<String, Cluster> clusterMap = getCheckedClusterMap(clusters);
for (final Cluster cluster : clusterMap.values()) {
Config falconEnvConfig = cluster.getDesiredConfigByType("falcon-env");
if (falconEnvConfig != null) {
Map<String, String> falconEnvEnvProperties = falconEnvConfig.getProperties();
if (falconEnvEnvProperties.containsKey("falcon_store_uri")) {
LOG.info("Removing property falcon_store_uri from falcon-env");
removeConfigurationPropertiesFromCluster(cluster, "falcon-env", Collections.singleton("falcon_store_uri"));
}
}
}
}
/**
* Updates the YARN Capacity Scheduler related configurations for the clusters managed by this Ambari
* Update services configuration to set proper leaf queue name for services
* update mapred-site, webhcat-site, tez-site, yarn-env
*
* @throws AmbariException if an error occurs while updating the configurations
*/
protected void updateQueueNameConfigs() throws AmbariException {
AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
Clusters clusters = ambariManagementController.getClusters();
Map<String, Cluster> clusterMap = getCheckedClusterMap(clusters);
for (final Cluster cluster : clusterMap.values()) {
Config capacityScheduler = cluster.getDesiredConfigByType(CAPACITY_SCHEDULER_CONFIG);
if (capacityScheduler != null) {
Map<String, String> capacitySchedulerProperties = capacityScheduler.getProperties();
Set<String> leafQueues;
leafQueues = getCapacitySchedulerLeafQueues(capacitySchedulerProperties);
Set<String> installedServices = cluster.getServices().keySet();
if (leafQueues ==null || leafQueues.isEmpty()) {
LOG.warn("There is no leafQueues in capacity-scheduler");
return;
}
if (installedServices.contains(cluster.getServiceByConfigType(WEBHCAT_SITE_CONFIG)) &&
!isQueueNameValid(cluster, leafQueues, WEBHCAT_SITE_QUEUE_NAME, WEBHCAT_SITE_CONFIG)){
updateQueueName(cluster, leafQueues, WEBHCAT_SITE_QUEUE_NAME, WEBHCAT_SITE_CONFIG);
}
if (installedServices.contains(cluster.getServiceByConfigType(TEZ_SITE_CONFIG)) &&
!isQueueNameValid(cluster, leafQueues, TEZ_SITE_QUEUE_NAME, TEZ_SITE_CONFIG)){
updateQueueName(cluster, leafQueues, TEZ_SITE_QUEUE_NAME, TEZ_SITE_CONFIG);
}
if (installedServices.contains(cluster.getServiceByConfigType(YARN_ENV_CONFIG)) &&
!isQueueNameValid(cluster, leafQueues, YARN_ENV_QUEUE_NAME, YARN_ENV_CONFIG)){
updateQueueName(cluster, leafQueues, YARN_ENV_QUEUE_NAME, YARN_ENV_CONFIG);
}
if (installedServices.contains(cluster.getServiceByConfigType(MAPRED_SITE_CONFIG)) &&
!isQueueNameValid(cluster, leafQueues, MAPRED_SITE_QUEUE_NAME, MAPRED_SITE_CONFIG)){
updateQueueName(cluster, leafQueues, MAPRED_SITE_QUEUE_NAME, MAPRED_SITE_CONFIG);
}
}
}
}
/**
* Updates the Spark-related configurations for the clusters managed by this Ambari
* Removes falcon_store_uri from falcon-env.
* Updates {{hdp_full_version}} to {{full_stack_version}}
* @throws AmbariException if an error occurs while updating the configurations
*/
protected void updateSparkConfigs() throws AmbariException {
AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
Clusters clusters = ambariManagementController.getClusters();
Map<String, Cluster> clusterMap = getCheckedClusterMap(clusters);
for (final Cluster cluster : clusterMap.values()) {
Config sparkDefaultsConfig = cluster.getDesiredConfigByType("spark-defaults");
if (sparkDefaultsConfig != null) {
Map<String, String> updates = new HashMap<>();
Map<String, String> sparkDefaultsProperties = sparkDefaultsConfig.getProperties();
if (sparkDefaultsProperties.containsKey("spark.driver.extraJavaOptions")) {
LOG.info("Updating property spark.driver.extraJavaOptions in spark-defaults");
String oldValue = sparkDefaultsProperties.get("spark.driver.extraJavaOptions");
if(oldValue.contains("{{hdp_full_version}}")) {
String newValue = oldValue.replace("{{hdp_full_version}}", "{{full_stack_version}}");
updates.put("spark.driver.extraJavaOptions", newValue);
}
}
if (sparkDefaultsProperties.containsKey("spark.yarn.am.extraJavaOptions")) {
LOG.info("Updating property spark.yarn.am.extraJavaOptions in spark-defaults");
String oldValue = sparkDefaultsProperties.get("spark.yarn.am.extraJavaOptions");
if(oldValue.contains("{{hdp_full_version}}")) {
String newValue = oldValue.replace("{{hdp_full_version}}", "{{full_stack_version}}");
updates.put("spark.yarn.am.extraJavaOptions", newValue);
}
}
if(updates.size() != 0 ) {
updateConfigurationPropertiesForCluster(cluster, "spark-defaults", updates, null, true, false);
}
}
Config sparkJavaOptsConfig = cluster.getDesiredConfigByType("spark-javaopts-properties");
if(sparkJavaOptsConfig != null) {
Map<String, String> updates = new HashMap<>();
Map<String, String> sparkJavaOptsProperties = sparkJavaOptsConfig.getProperties();
if (sparkJavaOptsProperties.containsKey("content")) {
String oldValue = sparkJavaOptsProperties.get("content");
if(oldValue.contains("{{hdp_full_version}}")) {
LOG.info("Updating property content in spark-javaopts-properties");
String newValue = oldValue.replace("{{hdp_full_version}}", "{{full_stack_version}}");
updates.put("content", newValue);
updateConfigurationPropertiesForCluster(cluster, "spark-javaopts-properties", updates, null, true, false);
}
}
}
}
}
/**
* Removes the HDFS/AMS alert definitions for the standard deviation alerts,
* including all history, notifications and groupings.
* <p/>
* These alerts shipped disabled and were not functional in prior versions of
* Ambari. This is the cleanest and simplest way to update them all as they
* will be read back into Ambari on server startup.
*
* @throws SQLException
*/
void removeStandardDeviationAlerts() throws SQLException {
List<String> deviationAlertNames = Lists.newArrayList(
"namenode_service_rpc_queue_latency_hourly",
"namenode_client_rpc_queue_latency_hourly",
"namenode_service_rpc_processing_latency_hourly",
"namenode_client_rpc_processing_latency_hourly",
"increase_nn_heap_usage_daily",
"namenode_service_rpc_processing_latency_daily",
"namenode_client_rpc_processing_latency_daily",
"namenode_service_rpc_queue_latency_daily",
"namenode_client_rpc_queue_latency_daily",
"namenode_increase_in_storage_capacity_usage_daily",
"increase_nn_heap_usage_weekly",
"namenode_increase_in_storage_capacity_usage_weekly");
AlertDefinitionDAO alertDefinitionDAO = injector.getInstance(AlertDefinitionDAO.class);
Clusters clusters = injector.getInstance(Clusters.class);
Map<String, Cluster> clusterMap = getCheckedClusterMap(clusters);
for (final Cluster cluster : clusterMap.values()) {
long clusterId = cluster.getClusterId();
for (String alertName : deviationAlertNames) {
AlertDefinitionEntity definition = alertDefinitionDAO.findByName(clusterId, alertName);
if (null != definition) {
alertDefinitionDAO.remove(definition);
}
}
}
}
/**
* Removes the Atlas meta-server alert definition, including all history, notifications and groupings.
*
* @throws SQLException
*/
void removeAtlasMetaserverAlert() throws SQLException {
AlertDefinitionDAO alertDefinitionDAO = injector.getInstance(AlertDefinitionDAO.class);
Clusters clusters = injector.getInstance(Clusters.class);
Map<String, Cluster> clusterMap = getCheckedClusterMap(clusters);
String atlas_metastore_alert_name = "metadata_server_process";
for (final Cluster cluster : clusterMap.values()) {
long clusterId = cluster.getClusterId();
AlertDefinitionEntity definition = alertDefinitionDAO.findByName(clusterId, atlas_metastore_alert_name);
if (null != definition) {
alertDefinitionDAO.remove(definition);
}
}
}
/**
* Ensures that each user has only one explicit role.
* <p>
* Before Ambari 2.4.0, users were allowed to have multiple permissions, which were like roles.
* In Ambari 2.4.0, the concept of roles was added, where each user may have a single role
* explicitly assigned - other roles may be assumed based on group assignments and access to views.
* <p>
* For each user, determine the set of explicitly set roles and prune off all but the role with
* the greater set of permissions.
*/
void consolidateUserRoles() {
LOG.info("Consolidating User Roles...");
List<UserEntity> users = userDAO.findAll();
if(users != null) {
for (UserEntity user : users) {
PrincipalEntity principal = user.getPrincipal();
if (principal != null) {
Set<PrivilegeEntity> privileges = principal.getPrivileges();
if (privileges != null) {
Map<ResourceEntity, Set<PrivilegeEntity>> resourceExplicitPrivileges = new HashMap<ResourceEntity, Set<PrivilegeEntity>>();
PrivilegeEntity ambariAdministratorPrivilege = null;
// Find the set of explicitly assigned roles per cluster
for (PrivilegeEntity privilege : privileges) {
ResourceEntity resource = privilege.getResource();
if (resource != null) {
ResourceTypeEntity resourceType = resource.getResourceType();
if (resourceType != null) {
String type = resourceType.getName();
// If the privilege is for the CLUSTER or AMBARI, it is an explicitly assigned role.
if (ResourceType.CLUSTER.name().equalsIgnoreCase(type)) {
// If the privilege is for a CLUSTER, create a map of cluster to roles.
Set<PrivilegeEntity> explicitPrivileges = resourceExplicitPrivileges.get(resource);
if (explicitPrivileges == null) {
explicitPrivileges = new HashSet<PrivilegeEntity>();
resourceExplicitPrivileges.put(resource, explicitPrivileges);
}
explicitPrivileges.add(privilege);
} else if (ResourceType.AMBARI.name().equalsIgnoreCase(type)) {
// If the privilege is for AMBARI, assume the user is an Ambari Administrator.
ambariAdministratorPrivilege = privilege;
}
}
}
}
if(ambariAdministratorPrivilege != null) {
// If the user is an Ambari admin, add that privilege to each set of privileges
for (Set<PrivilegeEntity> explicitPrivileges : resourceExplicitPrivileges.values()) {
explicitPrivileges.add(ambariAdministratorPrivilege);
}
}
// For each cluster resource, if the user has more than one role, prune off the lower
// privileged roles.
// If the user has roles for a cluster and is also an Ambari administrator
// (ambariAdministratorPrivilege is not null), the Ambari administrator role takes
// precedence over all other roles
for (Map.Entry<ResourceEntity, Set<PrivilegeEntity>> entry : resourceExplicitPrivileges.entrySet()) {
Set<PrivilegeEntity> explicitPrivileges = entry.getValue();
if (explicitPrivileges.size() > 1) {
LOG.info("{} has {} explicitly assigned roles for the cluster {}, consolidating...",
user.getUserName(), explicitPrivileges.size(), getClusterName(entry.getKey()));
PrivilegeEntity toKeep = null;
PrivilegeEntity toRemove = null;
for (PrivilegeEntity privilegeEntity : explicitPrivileges) {
if (toKeep == null) {
toKeep = privilegeEntity;
} else {
Integer toKeepLevel = ROLE_ORDER.get(toKeep.getPermission().getPermissionName());
Integer currentLevel = ROLE_ORDER.get(privilegeEntity.getPermission().getPermissionName());
// If the PrivilegeEntity currently set to be kept is ordered higher than the
// PrivilegeEntity being processed, move it to the list of PrivilegeEntities to
// be removed and remember the one being processed as the one the keep.
if (toKeepLevel > currentLevel) {
toRemove = toKeep;
toKeep = privilegeEntity;
}
else {
toRemove = privilegeEntity;
}
LOG.info("Removing the role {} from the set assigned to {} since {} is more powerful.",
toRemove.getPermission().getPermissionName(), user.getUserName(),
toKeep.getPermission().getPermissionName());
privilegeDAO.remove(toRemove);
}
}
}
}
}
}
}
}
}
/**
* Removes unnecessary authorizations(alert management) from CLUSTER.OPERATOR and SERVICE.ADMINISTRATOR.
*/
void removeAuthorizations(){
List<PermissionEntity> peList = new ArrayList<>();
for(String name : Arrays.asList("CLUSTER.OPERATOR", "SERVICE.ADMINISTRATOR")) {
PermissionEntity pe = permissionDAO.findPermissionByNameAndType(name, resourceTypeDAO.findByName("CLUSTER"));
if (pe != null) {
peList.add(pe);
}
}
for(PermissionEntity pe : peList) {
Collection<RoleAuthorizationEntity> authorizations = pe.getAuthorizations();
for (Iterator<RoleAuthorizationEntity> iterator = authorizations.iterator(); iterator.hasNext();) {
RoleAuthorizationEntity authorization = iterator.next();
if ("SERVICE.TOGGLE_ALERTS".equals(authorization.getAuthorizationId()) || "SERVICE.MANAGE_ALERTS".equals(authorization.getAuthorizationId())) {
iterator.remove();
}
}
permissionDAO.merge(pe);
}
}
/**
* {@inheritDoc}
*/
@Override
protected void updateKerberosDescriptorArtifact(ArtifactDAO artifactDAO, ArtifactEntity artifactEntity) throws AmbariException {
if (artifactEntity != null) {
Map<String, Object> data = artifactEntity.getArtifactData();
if (data != null) {
final KerberosDescriptor kerberosDescriptor = new KerberosDescriptorFactory().createInstance(data);
if (kerberosDescriptor != null) {
// Get the service that needs to be updated
KerberosServiceDescriptor serviceDescriptor = kerberosDescriptor.getService("HBASE");
if(serviceDescriptor != null) {
KerberosComponentDescriptor componentDescriptor = serviceDescriptor.getComponent("PHOENIX_QUERY_SERVER");
if (componentDescriptor != null) {
// Get the identity that needs to be updated
KerberosIdentityDescriptor origIdentityDescriptor = componentDescriptor.getIdentity("hbase_queryserver_hbase");
if (origIdentityDescriptor != null) {
// Create the new principal descriptor
KerberosPrincipalDescriptor origPrincipalDescriptor = origIdentityDescriptor.getPrincipalDescriptor();
KerberosPrincipalDescriptor newPrincipalDescriptor = new KerberosPrincipalDescriptor(
null,
null,
(origPrincipalDescriptor == null)
? "hbase-site/phoenix.queryserver.kerberos.principal"
: origPrincipalDescriptor.getConfiguration(),
null);
// Create the new keytab descriptor
KerberosKeytabDescriptor origKeytabDescriptor = origIdentityDescriptor.getKeytabDescriptor();
KerberosKeytabDescriptor newKeytabDescriptor = new KerberosKeytabDescriptor(
null,
null,
null,
null,
null,
(origKeytabDescriptor == null)
? "hbase-site/phoenix.queryserver.keytab.file"
: origKeytabDescriptor.getConfiguration(),
false);
// Remove the old identity
componentDescriptor.removeIdentity("hbase_queryserver_hbase");
// Add the new identity
componentDescriptor.putIdentity(new KerberosIdentityDescriptor("/spnego", newPrincipalDescriptor, newKeytabDescriptor, null));
artifactEntity.setArtifactData(kerberosDescriptor.toMap());
artifactDAO.merge(artifactEntity);
}
}
}
}
}
}
}
/**
* Given a {@link ResourceEntity}, attempts to find the relevant cluster's name.
*
* @param resourceEntity a {@link ResourceEntity}
* @return the relevant cluster's name
*/
private String getClusterName(ResourceEntity resourceEntity) {
ClusterEntity cluster = null;
ResourceTypeEntity resourceType = resourceEntity.getResourceType();
if (ResourceType.CLUSTER.name().equalsIgnoreCase(resourceType.getName())) {
cluster = clusterDAO.findByResourceId(resourceEntity.getId());
}
return (cluster == null) ? "_unknown_" : cluster.getClusterName();
}
protected void updateHDFSWidgetDefinition() throws AmbariException {
LOG.info("Updating HDFS widget definition.");
Map<String, List<String>> widgetMap = new HashMap<>();
Map<String, String> sectionLayoutMap = new HashMap<>();
List<String> hdfsSummaryWidgets = Collections.singletonList("NameNode Operations");
widgetMap.put("HDFS_SUMMARY", hdfsSummaryWidgets);
sectionLayoutMap.put("HDFS_SUMMARY", "default_hdfs_dashboard");
updateWidgetDefinitionsForService("HDFS", widgetMap, sectionLayoutMap);
}
private void updateWidgetDefinitionsForService(String serviceName, Map<String, List<String>> widgetMap,
Map<String, String> sectionLayoutMap) throws AmbariException {
AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
AmbariMetaInfo ambariMetaInfo = injector.getInstance(AmbariMetaInfo.class);
Type widgetLayoutType = new TypeToken<Map<String, List<WidgetLayout>>>(){}.getType();
Gson gson = injector.getInstance(Gson.class);
WidgetDAO widgetDAO = injector.getInstance(WidgetDAO.class);
Clusters clusters = ambariManagementController.getClusters();
Map<String, Cluster> clusterMap = getCheckedClusterMap(clusters);
for (final Cluster cluster : clusterMap.values()) {
long clusterID = cluster.getClusterId();
StackId stackId = cluster.getDesiredStackVersion();
Map<String, Object> widgetDescriptor = null;
StackInfo stackInfo = ambariMetaInfo.getStack(stackId.getStackName(), stackId.getStackVersion());
ServiceInfo serviceInfo = stackInfo.getService(serviceName);
if (serviceInfo == null) {
LOG.info("Skipping updating widget definition, because " + serviceName + " service is not present in cluster " +
"cluster_name= " + cluster.getClusterName());
continue;
}
for (String section : widgetMap.keySet()) {
List<String> widgets = widgetMap.get(section);
for (String widgetName : widgets) {
List<WidgetEntity> widgetEntities = widgetDAO.findByName(clusterID,
widgetName, "ambari", section);
if (widgetEntities != null && widgetEntities.size() > 0) {
WidgetEntity entityToUpdate = null;
if (widgetEntities.size() > 1) {
LOG.info("Found more that 1 entity with name = "+ widgetName +
" for cluster = " + cluster.getClusterName() + ", skipping update.");
} else {
entityToUpdate = widgetEntities.iterator().next();
}
if (entityToUpdate != null) {
LOG.info("Updating widget: " + entityToUpdate.getWidgetName());
// Get the definition from widgets.json file
WidgetLayoutInfo targetWidgetLayoutInfo = null;
File widgetDescriptorFile = serviceInfo.getWidgetsDescriptorFile();
if (widgetDescriptorFile != null && widgetDescriptorFile.exists()) {
try {
widgetDescriptor = gson.fromJson(new FileReader(widgetDescriptorFile), widgetLayoutType);
} catch (Exception ex) {
String msg = "Error loading widgets from file: " + widgetDescriptorFile;
LOG.error(msg, ex);
widgetDescriptor = null;
}
}
if (widgetDescriptor != null) {
LOG.debug("Loaded widget descriptor: " + widgetDescriptor);
for (Object artifact : widgetDescriptor.values()) {
List<WidgetLayout> widgetLayouts = (List<WidgetLayout>) artifact;
for (WidgetLayout widgetLayout : widgetLayouts) {
if (widgetLayout.getLayoutName().equals(sectionLayoutMap.get(section))) {
for (WidgetLayoutInfo layoutInfo : widgetLayout.getWidgetLayoutInfoList()) {
if (layoutInfo.getWidgetName().equals(widgetName)) {
targetWidgetLayoutInfo = layoutInfo;
}
}
}
}
}
}
if (targetWidgetLayoutInfo != null) {
entityToUpdate.setMetrics(gson.toJson(targetWidgetLayoutInfo.getMetricsInfo()));
entityToUpdate.setWidgetValues(gson.toJson(targetWidgetLayoutInfo.getValues()));
entityToUpdate.setDescription(targetWidgetLayoutInfo.getDescription());
widgetDAO.merge(entityToUpdate);
} else {
LOG.warn("Unable to find widget layout info for " + widgetName +
" in the stack: " + stackId);
}
}
}
}
}
}
}
/**
* @return True if the stack is >=HDP-2.5, false otherwise.
*/
protected boolean isAtLeastHdp25(StackId stackId) {
if (null == stackId) {
return false;
}
try {
return stackId.compareTo(new StackId("HDP-2.5")) >= 0;
} catch (Exception e) {
// Different stack names throw an exception.
return false;
}
}
/**
* Update Phoenix Query Server Kerberos configurations. Ambari 2.4 will alter the Phoenix Query Server to
* supporting SPNEGO authentication which requires that the "HTTP/_HOST" principal and corresponding
* keytab file instead of the generic HBase service keytab and principal it previously had.
*/
protected void updatePhoenixConfigs() throws AmbariException {
final AmbariManagementController controller = injector.getInstance(AmbariManagementController.class);
final Clusters clusters = controller.getClusters();
if (null != clusters) {
Map<String, Cluster> clusterMap = clusters.getClusters();
if (null != clusterMap && !clusterMap.isEmpty()) {
for (final Cluster cluster : clusterMap.values()) {
Set<String> installedServices = cluster.getServices().keySet();
StackId stackId = cluster.getCurrentStackVersion();
// HBase is installed and Kerberos is enabled
if (installedServices.contains("HBASE") && SecurityType.KERBEROS == cluster.getSecurityType() && isAtLeastHdp25(stackId)) {
Config hbaseSite = cluster.getDesiredConfigByType(HBASE_SITE_CONFIG);
if (null != hbaseSite) {
Map<String, String> hbaseSiteProperties = hbaseSite.getProperties();
// Get Phoenix Query Server kerberos config properties
String pqsKrbPrincipal = hbaseSiteProperties.get(PHOENIX_QUERY_SERVER_PRINCIPAL_KEY);
String pqsKrbKeytab = hbaseSiteProperties.get(PHOENIX_QUERY_SERVER_KEYTAB_KEY);
// Principal and Keytab are set
if (null != pqsKrbPrincipal && null != pqsKrbKeytab) {
final Map<String, String> updatedKerberosProperties = new HashMap<>();
final KerberosDescriptor defaultDescriptor = getKerberosDescriptor(cluster);
KerberosIdentityDescriptor spnegoDescriptor = defaultDescriptor.getIdentity("spnego");
if (null != spnegoDescriptor) {
// Add the SPNEGO config for the principal
KerberosPrincipalDescriptor principalDescriptor = spnegoDescriptor.getPrincipalDescriptor();
if (null != principalDescriptor) {
updatedKerberosProperties.put(PHOENIX_QUERY_SERVER_PRINCIPAL_KEY, principalDescriptor.getValue());
}
// Add the SPNEGO config for the keytab
KerberosKeytabDescriptor keytabDescriptor = spnegoDescriptor.getKeytabDescriptor();
if (null != keytabDescriptor) {
updatedKerberosProperties.put(PHOENIX_QUERY_SERVER_KEYTAB_KEY, keytabDescriptor.getFile());
}
// Update the configuration if we changed anything
if (!updatedKerberosProperties.isEmpty()) {
updateConfigurationProperties(HBASE_SITE_CONFIG, updatedKerberosProperties, true, false);
}
}
}
}
}
}
}
}
}
/**
* Update properties with name
* yarn.timeline-server.url to yarn.ats.url
*/
private void updateTezViewProperty() throws SQLException {
dbAccessor.executeUpdate("UPDATE viewinstanceproperty SET name = 'yarn.ats.url' where name = 'yarn.timeline-server.url'");
}
/**
* Update view instance table's cluster_handle column to have cluster_id
* instead of cluster_name
*/
@Transactional
private void updateViewInstanceTable() throws SQLException {
try {
if (Long.class.equals(dbAccessor.getColumnClass(VIEWINSTANCE_TABLE, CLUSTER_HANDLE_COLUMN))) {
LOG.info(String.format("%s column is already numeric. Skipping an update of %s table.", CLUSTER_HANDLE_COLUMN, VIEWINSTANCE_TABLE));
return;
}
} catch (ClassNotFoundException e) {
LOG.warn("Cannot determine a type of " + CLUSTER_HANDLE_COLUMN + " column.");
}
String cluster_handle_dummy = "cluster_handle_dummy";
dbAccessor.addColumn(VIEWINSTANCE_TABLE,
new DBColumnInfo(cluster_handle_dummy, Long.class, null, null, true));
Statement statement = null;
ResultSet resultSet = null;
try {
statement = dbAccessor.getConnection().createStatement();
if (statement != null) {
String selectSQL = String.format("SELECT cluster_id, cluster_name FROM %s",
CLUSTER_TABLE);
resultSet = statement.executeQuery(selectSQL);
//Getting 1st cluster and updating view instance table with cluster_id
if (null != resultSet && resultSet.next()) {
final Long clusterId = resultSet.getLong("cluster_id");
String updateSQL = String.format(
"UPDATE %s SET %s = %d WHERE cluster_handle IS NOT NULL",
VIEWINSTANCE_TABLE, cluster_handle_dummy, clusterId);
dbAccessor.executeQuery(updateSQL);
}
}
} finally {
JdbcUtils.closeResultSet(resultSet);
JdbcUtils.closeStatement(statement);
}
dbAccessor.dropColumn(VIEWINSTANCE_TABLE, CLUSTER_HANDLE_COLUMN);
dbAccessor.renameColumn(VIEWINSTANCE_TABLE, cluster_handle_dummy,
new DBColumnInfo(CLUSTER_HANDLE_COLUMN, Long.class, null, null, true));
}
/**
* If Capacity Scheduler instances configured as CUSTOM
* then upgrade them to Remote cluster
*
* @throws SQLException
*/
protected void upgradeCapSchedulerView() throws SQLException {
String capSchedulerViewName = "CAPACITY-SCHEDULER{1.0.0}";
RemoteAmbariClusterDAO remoteClusterDAO = injector.getInstance(RemoteAmbariClusterDAO.class);
ViewInstanceDAO instanceDAO = injector.getInstance(ViewInstanceDAO.class);
List<ViewInstanceEntity> instances = instanceDAO.findAll();
for (ViewInstanceEntity instance : instances) {
if (instance.getViewName().equals(capSchedulerViewName) && instance.getClusterHandle() == null) {
RemoteAmbariClusterEntity clusterEntity = new RemoteAmbariClusterEntity();
clusterEntity.setName(instance.getName() + "-cluster");
Map<String, String> propertyMap = instance.getPropertyMap();
String url = propertyMap.get("ambari.server.url");
String password = propertyMap.get("ambari.server.password");
String username = propertyMap.get("ambari.server.username");
if (StringUtils.isEmpty(url) || StringUtils.isEmpty(username) || StringUtils.isEmpty(password)) {
LOG.info("One of url, username, password is empty. Skipping upgrade for View Instance {}.", instance.getName());
continue;
}
clusterEntity.setUrl(url);
clusterEntity.setUsername(username);
try {
clusterEntity.setPassword(new DefaultMasker().unmask(password));
} catch (MaskException e) {
// ignore
}
remoteClusterDAO.save(clusterEntity);
instance.setClusterHandle(clusterEntity.getId());
instance.setClusterType(ClusterType.REMOTE_AMBARI);
instanceDAO.merge(instance);
}
}
}
void fixAuthorizationDescriptions() throws SQLException {
RoleAuthorizationDAO roleAuthorizationDAO = injector.getInstance(RoleAuthorizationDAO.class);
RoleAuthorizationEntity roleAuthorization = roleAuthorizationDAO.findById("SERVICE.ADD_DELETE_SERVICES");
if (roleAuthorization != null) {
roleAuthorization.setAuthorizationName("Add/delete services");
roleAuthorizationDAO.merge(roleAuthorization);
}
}
protected void updateRangerHbasePluginProperties() throws AmbariException {
AmbariManagementController ambariManagementController = injector.getInstance(AmbariManagementController.class);
Clusters clusters = ambariManagementController.getClusters();
if (clusters != null) {
Map<String, Cluster> clusterMap = clusters.getClusters();
if (clusterMap != null && !clusterMap.isEmpty()) {
for (final Cluster cluster : clusterMap.values()) {
Set<String> installedServices = cluster.getServices().keySet();
if (installedServices.contains("HBASE") && installedServices.contains("RANGER")) {
Config rangerHbasePluginProperties = cluster.getDesiredConfigByType("ranger-hbase-plugin-properties");
Config clusterEnv = cluster.getDesiredConfigByType("cluster-env");
if (rangerHbasePluginProperties != null && clusterEnv != null) {
String smokeUserName = clusterEnv.getProperties().get("smokeuser");
String policyUser = rangerHbasePluginProperties.getProperties().get("policy_user");
if (policyUser != null && smokeUserName != null && !policyUser.equals(smokeUserName) && policyUser.equals("ambari-qa")) {
updateConfigurationProperties("ranger-hbase-plugin-properties", Collections.singletonMap("policy_user", smokeUserName), true, false);
}
}
}
}
}
}
}
/**
* Update HBase Kerberos configurations. Ambari 2.4 will alter the HBase web UIs to
* support SPNEGO authentication. HBase needs to have new keytab and principal properties
* to enable SPNEGO authentication (if the user so chooses to enable it).
*/
protected void updateHBaseConfigs() throws AmbariException {
final AmbariManagementController controller = injector.getInstance(AmbariManagementController.class);
final Clusters clusters = controller.getClusters();
if (null != clusters) {
Map<String, Cluster> clusterMap = clusters.getClusters();
if (null != clusterMap && !clusterMap.isEmpty()) {
for (final Cluster cluster : clusterMap.values()) {
Set<String> installedServices = cluster.getServices().keySet();
StackId stackId = cluster.getCurrentStackVersion();
// HBase is installed and Kerberos is enabled
if (installedServices.contains("HBASE") && SecurityType.KERBEROS == cluster.getSecurityType()) {
Config hbaseSite = cluster.getDesiredConfigByType(HBASE_SITE_CONFIG);
if (null != hbaseSite) {
Map<String, String> hbaseSiteProperties = hbaseSite.getProperties();
// update classes based on krb/ranger availability
boolean enableRangerHbase = false;
boolean xmlConfigurationsSupported = false;
Config rangerHbasePluginProperties = cluster.getDesiredConfigByType("ranger-hbase-plugin-properties");
if (rangerHbasePluginProperties != null && rangerHbasePluginProperties.getProperties().containsKey("ranger-hbase-plugin-enabled")) {
enableRangerHbase = rangerHbasePluginProperties.getProperties().get("ranger-hbase-plugin-enabled").toLowerCase() == "yes";
}
Config rangerEnv = cluster.getDesiredConfigByType("ranger-env");
if (rangerEnv != null && rangerEnv.getProperties().containsKey("xml_configurations_supported")) {
xmlConfigurationsSupported = Boolean.parseBoolean(rangerEnv.getProperties().get("xml_configurations_supported"));
}
final Map<String, String> updatedHbaseProperties = new HashMap<>();
if (hbaseSiteProperties.containsKey("hbase.coprocessor.master.classes") &&
hbaseSiteProperties.get("hbase.coprocessor.master.classes").equals("{{hbase_coprocessor_master_classes}}")) {
if (!enableRangerHbase) {
updatedHbaseProperties.put("hbase.coprocessor.master.classes", "org.apache.hadoop.hbase.security.access.AccessController");
} else if (xmlConfigurationsSupported) {
updatedHbaseProperties.put("hbase.coprocessor.master.classes", "org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor");
} else {
updatedHbaseProperties.put("hbase.coprocessor.master.classes", "com.xasecure.authorization.hbase.XaSecureAuthorizationCoprocessor");
}
}
if (hbaseSiteProperties.containsKey("hbase.coprocessor.regionserver.classes") &&
hbaseSiteProperties.get("hbase.coprocessor.regionserver.classes").equals("{{hbase_coprocessor_regionserver_classes}}")) {
if (!enableRangerHbase) {
updatedHbaseProperties.put("hbase.coprocessor.regionserver.classes", "org.apache.hadoop.hbase.security.access.AccessController");
} else if (xmlConfigurationsSupported) {
updatedHbaseProperties.put("hbase.coprocessor.regionserver.classes", "org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor");
} else {
updatedHbaseProperties.put("hbase.coprocessor.regionserver.classes", "com.xasecure.authorization.hbase.XaSecureAuthorizationCoprocessor");
}
}
if (hbaseSiteProperties.containsKey("hbase.coprocessor.region.classes") &&
hbaseSiteProperties.get("hbase.coprocessor.region.classes").equals("{{hbase_coprocessor_region_classes}}")) {
if (!enableRangerHbase) {
updatedHbaseProperties.put("hbase.coprocessor.region.classes", "org.apache.hadoop.hbase.security.token.TokenProvider,org.apache.hadoop.hbase.security.access.SecureBulkLoadEndpoint,org.apache.hadoop.hbase.security.access.AccessController");
} else if (xmlConfigurationsSupported) {
updatedHbaseProperties.put("hbase.coprocessor.region.classes", "org.apache.hadoop.hbase.security.token.TokenProvider,org.apache.hadoop.hbase.security.access.SecureBulkLoadEndpoint,org.apache.ranger.authorization.hbase.RangerAuthorizationCoprocessor");
} else {
updatedHbaseProperties.put("hbase.coprocessor.region.classes", "org.apache.hadoop.hbase.security.token.TokenProvider,org.apache.hadoop.hbase.security.access.SecureBulkLoadEndpoint,com.xasecure.authorization.hbase.XaSecureAuthorizationCoprocessor");
}
}
updateConfigurationProperties(HBASE_SITE_CONFIG, updatedHbaseProperties, true, false);
if (isAtLeastHdp25(stackId)) {
// Get any existing config properties (they probably don't exist)
String principal = hbaseSiteProperties.get(HBASE_SPNEGO_PRINCIPAL_KEY);
String keytab = hbaseSiteProperties.get(HBASE_SPNEGO_KEYTAB_KEY);
final Map<String, String> updatedKerberosProperties = new HashMap<>();
// Set the principal for SPNEGO if it's not already set
if (null == principal) {
final KerberosDescriptor defaultDescriptor = getKerberosDescriptor(cluster);
final KerberosIdentityDescriptor spnegoDescriptor = defaultDescriptor.getIdentity("spnego");
if (null != spnegoDescriptor) {
// Add the SPNEGO config for the principal
KerberosPrincipalDescriptor principalDescriptor = spnegoDescriptor.getPrincipalDescriptor();
if (null != principalDescriptor) {
updatedKerberosProperties.put(HBASE_SPNEGO_PRINCIPAL_KEY, principalDescriptor.getValue());
}
}
}
// Set the keytab for SPNEGO if it's not already set
if (null == keytab) {
final KerberosDescriptor defaultDescriptor = getKerberosDescriptor(cluster);
final KerberosIdentityDescriptor spnegoDescriptor = defaultDescriptor.getIdentity("spnego");
if (null != spnegoDescriptor) {
// Add the SPNEGO config for the keytab
KerberosKeytabDescriptor keytabDescriptor = spnegoDescriptor.getKeytabDescriptor();
if (null != keytabDescriptor) {
updatedKerberosProperties.put(HBASE_SPNEGO_KEYTAB_KEY, keytabDescriptor.getFile());
}
}
}
// Update the configuration if we changed anything
if (!updatedKerberosProperties.isEmpty()) {
updateConfigurationProperties(HBASE_SITE_CONFIG, updatedKerberosProperties, true, false);
}
}
}
}
}
}
}
}
/**
* Update somketestentity class for pig view in viewentity table
*/
protected void updatePigSmokeTestEntityClass() throws SQLException {
String updateSQL = "UPDATE viewentity " +
"SET class_name = 'org.apache.ambari.view.pig.persistence.SmokeTestEntity' " +
"WHERE class_name = 'org.apache.ambari.view.pig.persistence.DataStoreStorage$SmokeTestEntity'";
dbAccessor.executeUpdate(updateSQL);
}
}