/* * 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 java.sql.SQLException; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.configuration.Configuration; import org.apache.ambari.server.orm.DBAccessor; 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.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.ResourceEntity; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.google.inject.Inject; import com.google.inject.Injector; import com.google.inject.persist.Transactional; /** * Upgrade catalog for version 2.4.2. */ public class UpgradeCatalog242 extends AbstractUpgradeCatalog { protected static final String EXTENSION_TABLE = "extension"; protected static final String USERS_TABLE = "users"; protected static final String HOST_ROLE_COMMAND_TABLE = "host_role_command"; protected static final String BLUEPRINT_TABLE = "blueprint"; protected static final String HOST_GROUP_TABLE = "hostgroup"; protected static final String BLUEPRINT_CONFIGURATION = "blueprint_configuration"; protected static final String BLUEPRINT_SETTING = "blueprint_setting"; protected static final String HOSTGROUP_COMPONENT = "hostgroup_component"; protected static final String HOSTGROUP_CONFIGURATION = "hostgroup_configuration"; protected static final String BLUEPRINT_NAME_COLUMN = "blueprint_name"; protected static final String EXTENSION_NAME_COLUMN = "extension_name"; protected static final String EXTENSION_VERSION_COLUMN = "extension_version"; protected static final String USER_TYPE_COLUMN = "user_type"; protected static final String USER_NAME_COLUMN = "user_name"; protected static final String ROLE_COLUMN = "role"; protected static final String STATUS_COLUMN = "status"; protected static final String NAME_COLUMN = "name"; /** * Logger. */ private static final Logger LOG = LoggerFactory.getLogger(UpgradeCatalog242.class); // ----- 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 UpgradeCatalog242(Injector injector) { super(injector); this.injector = injector; } // ----- UpgradeCatalog ---------------------------------------------------- /** * {@inheritDoc} */ @Override public String getTargetVersion() { return "2.4.2"; } // ----- AbstractUpgradeCatalog -------------------------------------------- /** * {@inheritDoc} */ @Override public String getSourceVersion() { return "2.4.0.2"; } @Override protected void executeDDLUpdates() throws AmbariException, SQLException { updateTablesForMysql(); } @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(); createRoleAuthorizations(); convertRolePrincipals(); } /** * Create new role authorizations: CLUSTER.RUN_CUSTOM_COMMAND and AMBARI.RUN_CUSTOM_COMMAND * * @throws SQLException */ @Transactional protected void createRoleAuthorizations() throws SQLException { addRoleAuthorization("CLUSTER.RUN_CUSTOM_COMMAND", "Perform custom cluster-level actions", Arrays.asList("AMBARI.ADMINISTRATOR:AMBARI", "CLUSTER.ADMINISTRATOR:CLUSTER")); addRoleAuthorization("AMBARI.RUN_CUSTOM_COMMAND", "Perform custom administrative actions", Collections.singletonList("AMBARI.ADMINISTRATOR:AMBARI")); } protected void updateTablesForMysql() throws SQLException { final Configuration.DatabaseType databaseType = configuration.getDatabaseType(); if (databaseType == Configuration.DatabaseType.MYSQL) { dbAccessor.alterColumn(EXTENSION_TABLE, new DBAccessor.DBColumnInfo(EXTENSION_NAME_COLUMN, String.class, 100, null, false)); dbAccessor.alterColumn(EXTENSION_TABLE, new DBAccessor.DBColumnInfo(EXTENSION_VERSION_COLUMN, String.class, 100, null, false)); dbAccessor.alterColumn(USERS_TABLE, new DBAccessor.DBColumnInfo(USER_TYPE_COLUMN, String.class, 100, null, false)); dbAccessor.alterColumn(USERS_TABLE, new DBAccessor.DBColumnInfo(USER_NAME_COLUMN, String.class, 100, null, false)); dbAccessor.alterColumn(HOST_ROLE_COMMAND_TABLE, new DBAccessor.DBColumnInfo(ROLE_COLUMN, String.class, 100, null, true)); dbAccessor.alterColumn(HOST_ROLE_COMMAND_TABLE, new DBAccessor.DBColumnInfo(STATUS_COLUMN, String.class, 100, null, true)); dbAccessor.dropFKConstraint(HOST_GROUP_TABLE, "FK_hg_blueprint_name"); dbAccessor.dropFKConstraint(HOST_GROUP_TABLE, "FK_hostgroup_blueprint_name"); dbAccessor.dropFKConstraint(BLUEPRINT_CONFIGURATION, "FK_cfg_blueprint_name"); dbAccessor.dropFKConstraint(BLUEPRINT_CONFIGURATION, "FK_blueprint_configuration_blueprint_name"); dbAccessor.dropFKConstraint(BLUEPRINT_SETTING, "FK_blueprint_setting_blueprint_name"); dbAccessor.dropFKConstraint(BLUEPRINT_SETTING, "FK_blueprint_setting_name"); dbAccessor.alterColumn(BLUEPRINT_TABLE, new DBAccessor.DBColumnInfo(BLUEPRINT_NAME_COLUMN, String.class, 100, null, false)); String[] uniqueColumns1 = new String[] { BLUEPRINT_NAME_COLUMN }; dbAccessor.addFKConstraint(HOST_GROUP_TABLE, "FK_hg_blueprint_name", uniqueColumns1, BLUEPRINT_TABLE, uniqueColumns1, false); dbAccessor.addFKConstraint(BLUEPRINT_CONFIGURATION, "FK_cfg_blueprint_name", uniqueColumns1, BLUEPRINT_TABLE, uniqueColumns1, false); dbAccessor.addFKConstraint(BLUEPRINT_SETTING, "FK_blueprint_setting_name", uniqueColumns1, BLUEPRINT_TABLE, uniqueColumns1, false); } } /** * Convert the previously set inherited privileges to the more generic inherited privileges model * based on role-based principals rather than specialized principal types. */ @Transactional void convertRolePrincipals() { LOG.info("Converting pseudo principle types to role principals"); PermissionDAO permissionDAO = injector.getInstance(PermissionDAO.class); PrivilegeDAO privilegeDAO = injector.getInstance(PrivilegeDAO.class); PrincipalDAO principalDAO = injector.getInstance(PrincipalDAO.class); PrincipalTypeDAO principalTypeDAO = injector.getInstance(PrincipalTypeDAO.class); Map<String, String> principalTypeToRole = new HashMap<>(); principalTypeToRole.put("ALL.CLUSTER.ADMINISTRATOR", "CLUSTER.ADMINISTRATOR"); principalTypeToRole.put("ALL.CLUSTER.OPERATOR", "CLUSTER.OPERATOR"); principalTypeToRole.put("ALL.CLUSTER.USER", "CLUSTER.USER"); principalTypeToRole.put("ALL.SERVICE.ADMINISTRATOR", "SERVICE.ADMINISTRATOR"); principalTypeToRole.put("ALL.SERVICE.OPERATOR", "SERVICE.OPERATOR"); // Handle a typo introduced in org.apache.ambari.server.upgrade.UpgradeCatalog240.updateClusterInheritedPermissionsConfig principalTypeToRole.put("ALL.SERVICE.OPERATIOR", "SERVICE.OPERATOR"); for (Map.Entry<String, String> entry : principalTypeToRole.entrySet()) { String principalTypeName = entry.getKey(); String roleName = entry.getValue(); PermissionEntity role = permissionDAO.findByName(roleName); PrincipalEntity rolePrincipalEntity = (role == null) ? null : role.getPrincipal(); // Convert Privilege Records PrincipalTypeEntity principalTypeEntity = principalTypeDAO.findByName(principalTypeName); if (principalTypeEntity != null) { List<PrincipalEntity> principalEntities = principalDAO.findByPrincipalType(principalTypeName); for (PrincipalEntity principalEntity : principalEntities) { Set<PrivilegeEntity> privilegeEntities = principalEntity.getPrivileges(); for (PrivilegeEntity privilegeEntity : privilegeEntities) { if (rolePrincipalEntity == null) { LOG.info("Removing privilege (id={}) since no role principle was found for {}:\n{}", privilegeEntity.getId(), roleName, formatPrivilegeEntityDetails(privilegeEntity)); // Remove this privilege privilegeDAO.remove(privilegeEntity); } else { LOG.info("Updating privilege (id={}) to use role principle for {}:\n{}", privilegeEntity.getId(), roleName, formatPrivilegeEntityDetails(privilegeEntity)); // Set the principal to the updated principal value privilegeEntity.setPrincipal(rolePrincipalEntity); privilegeDAO.merge(privilegeEntity); } } // Remove the obsolete principal principalDAO.remove(principalEntity); } // Remove the obsolete principal type principalTypeDAO.remove(principalTypeEntity); } } LOG.info("Converting pseudo principle types to role principals - complete."); } private String formatPrivilegeEntityDetails(PrivilegeEntity privilegeEntity) { if (privilegeEntity == null) { return ""; } else { ResourceEntity resource = privilegeEntity.getResource(); PrincipalEntity principal = privilegeEntity.getPrincipal(); PermissionEntity permission = privilegeEntity.getPermission(); return String.format("" + "\tPrivilege ID: %d" + "\n\tResource ID: %d" + "\n\tPrincipal ID: %d" + "\n\tPermission ID: %d", privilegeEntity.getId(), resource.getId(), principal.getId(), permission.getId() ); } } }