CLOUDSTACK-10236: Enable dynamic roles for missing props file (#2426)

Automate dynamic roles migration for missing props file

- In case commands.properties file is missing, enables dynamic roles.
- Adds a new -D or --default flag to migrate-dynamicroles.py script
  to simply update the global setting and use the default role-rule
  permissions.
- Add warning message, ask admins to move to dynamic roles during upgrade

Signed-off-by: Rohit Yadav <rohit.yadav@shapeblue.com>
This commit is contained in:
Rohit Yadav 2018-01-24 13:11:08 +01:00 committed by GitHub
parent 61a5a29705
commit 170b6ce20d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 37 additions and 9 deletions

View File

@ -31,6 +31,7 @@ import org.apache.commons.codec.binary.Base64;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import com.cloud.hypervisor.Hypervisor; import com.cloud.hypervisor.Hypervisor;
import com.cloud.utils.PropertiesUtil;
import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.exception.CloudRuntimeException;
public class Upgrade41000to41100 implements DbUpgrade { public class Upgrade41000to41100 implements DbUpgrade {
@ -65,10 +66,27 @@ public class Upgrade41000to41100 implements DbUpgrade {
@Override @Override
public void performDataMigration(Connection conn) { public void performDataMigration(Connection conn) {
checkAndEnableDynamicRoles(conn);
validateUserDataInBase64(conn); validateUserDataInBase64(conn);
updateSystemVmTemplates(conn); updateSystemVmTemplates(conn);
} }
private void checkAndEnableDynamicRoles(final Connection conn) {
final Map<String, String> apiMap = PropertiesUtil.processConfigFile(new String[] { "commands.properties" });
if (apiMap == null || apiMap.isEmpty()) {
if (LOG.isDebugEnabled()) {
LOG.debug("No commands.properties file was found, enabling dynamic roles by setting dynamic.apichecker.enabled to true if not already enabled.");
}
try (final PreparedStatement updateStatement = conn.prepareStatement("INSERT INTO cloud.configuration (category, instance, name, default_value, value) VALUES ('Advanced', 'DEFAULT', 'dynamic.apichecker.enabled', 'false', 'true') ON DUPLICATE KEY UPDATE value='true'")) {
updateStatement.executeUpdate();
} catch (SQLException e) {
LOG.error("Failed to set dynamic.apichecker.enabled to true, please run migrate-dynamicroles.py script to manually migrate to dynamic roles.", e);
}
} else {
LOG.warn("Old commands.properties static checker is deprecated, please use migrate-dynamicroles.py to migrate to dynamic roles. Refer http://docs.cloudstack.apache.org/projects/cloudstack-administration/en/latest/accounts.html#using-dynamic-roles");
}
}
private void validateUserDataInBase64(Connection conn) { private void validateUserDataInBase64(Connection conn) {
try (final PreparedStatement selectStatement = conn.prepareStatement("SELECT `id`, `user_data` FROM `cloud`.`user_vm` WHERE `user_data` IS NOT NULL;"); try (final PreparedStatement selectStatement = conn.prepareStatement("SELECT `id`, `user_data` FROM `cloud`.`user_vm` WHERE `user_data` IS NOT NULL;");
final ResultSet selectResultSet = selectStatement.executeQuery()) { final ResultSet selectResultSet = selectStatement.executeQuery()) {

View File

@ -39,6 +39,7 @@ import com.cloud.utils.component.PluggableService;
// This is the default API access checker that grab's the user's account // This is the default API access checker that grab's the user's account
// based on the account type, access is granted // based on the account type, access is granted
@Deprecated
public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIChecker { public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIChecker {
protected static final Logger LOGGER = Logger.getLogger(StaticRoleBasedAPIAccessChecker.class); protected static final Logger LOGGER = Logger.getLogger(StaticRoleBasedAPIAccessChecker.class);

View File

@ -55,6 +55,14 @@ def migrateApiRolePermissions(apis, conn):
if (octetKey[role] & int(apis[api])) > 0: if (octetKey[role] & int(apis[api])) > 0:
runSql(conn, "INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), %d, '%s', 'ALLOW', %d);" % (role, api, sortOrder)) runSql(conn, "INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), %d, '%s', 'ALLOW', %d);" % (role, api, sortOrder))
sortOrder += 1 sortOrder += 1
print("Static role permissions from commands.properties have been migrated into the db")
def enableDynamicApiChecker(conn):
runSql(conn, "UPDATE `cloud`.`configuration` SET value='true' where name='dynamic.apichecker.enabled'")
conn.commit()
conn.close()
print("Dynamic role based API checker has been enabled!")
def main(): def main():
@ -71,6 +79,8 @@ def main():
help="Host or IP of the MySQL server") help="Host or IP of the MySQL server")
parser.add_option("-f", "--properties-file", action="store", type="string", dest="commandsfile", default="/etc/cloudstack/management/commands.properties", parser.add_option("-f", "--properties-file", action="store", type="string", dest="commandsfile", default="/etc/cloudstack/management/commands.properties",
help="The commands.properties file") help="The commands.properties file")
parser.add_option("-D", "--default", action="store_true", dest="defaultRules", default=False,
help="")
parser.add_option("-d", "--dryrun", action="store_true", dest="dryrun", default=False, parser.add_option("-d", "--dryrun", action="store_true", dest="dryrun", default=False,
help="Dry run and debug operations this tool will perform") help="Dry run and debug operations this tool will perform")
(options, args) = parser.parse_args() (options, args) = parser.parse_args()
@ -89,8 +99,14 @@ def main():
port=int(options.port), port=int(options.port),
db=options.db) db=options.db)
if options.defaultRules:
print("Applying the default role permissions, ignoring any provided properties files(s).")
enableDynamicApiChecker(conn)
sys.exit(0)
if not os.path.isfile(options.commandsfile): if not os.path.isfile(options.commandsfile):
print("Provided commands.properties cannot be accessed or does not exist, please check check permissions") print("Provided commands.properties cannot be accessed or does not exist.")
print("Please check passed options, or run only with --default option to use the default role permissions.")
sys.exit(1) sys.exit(1)
while True: while True:
@ -122,15 +138,8 @@ def main():
# Migrate rules from commands.properties to cloud.role_permissions # Migrate rules from commands.properties to cloud.role_permissions
migrateApiRolePermissions(apiMap, conn) migrateApiRolePermissions(apiMap, conn)
print("Static role permissions from commands.properties have been migrated into the db")
# Enable dynamic role based API checker
runSql(conn, "UPDATE `cloud`.`configuration` SET value='true' where name='dynamic.apichecker.enabled'")
conn.commit()
conn.close()
print("Dynamic role based API checker has been enabled!")
enableDynamicApiChecker(conn)
if __name__ == '__main__': if __name__ == '__main__':
main() main()