From 679cb208dadb4457ae94db1c5fe8d61e45919bb1 Mon Sep 17 00:00:00 2001 From: davidjumani Date: Tue, 22 Jun 2021 12:38:33 +0530 Subject: [PATCH 1/6] Allow domain admin to change domain and account settings --- .../apache/cloudstack/query/QueryService.java | 3 +++ .../META-INF/db/schema-41510to41600.sql | 5 +++- .../com/cloud/api/query/QueryManagerImpl.java | 2 +- .../ConfigurationManagerImpl.java | 20 +++++++++++++++ .../cloud/server/ManagementServerImpl.java | 25 ++++++++++++++++--- 5 files changed, 50 insertions(+), 5 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/query/QueryService.java b/api/src/main/java/org/apache/cloudstack/query/QueryService.java index 3484de84ef49..6ff847a1683b 100644 --- a/api/src/main/java/org/apache/cloudstack/query/QueryService.java +++ b/api/src/main/java/org/apache/cloudstack/query/QueryService.java @@ -96,6 +96,9 @@ public interface QueryService { "user.vm.denied.details", "rootdisksize, cpuOvercommitRatio, memoryOvercommitRatio, Message.ReservedCapacityFreed.Flag", "Determines whether users can view certain VM settings. When set to empty, default value used is: rootdisksize, cpuOvercommitRatio, memoryOvercommitRatio, Message.ReservedCapacityFreed.Flag.", true); + static final ConfigKey DomainAdminAllowListedConfigurations = new ConfigKey("Advanced", String.class, + "domain.admin.allowlisted.config", "", "Determines which domain and account level configurations the domain admin is able to change", true); + static final ConfigKey UserVMReadOnlyDetails = new ConfigKey("Advanced", String.class, "user.vm.readonly.details", "dataDiskController, rootDiskController", "List of read-only VM settings/details as comma separated string", true); diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql b/engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql index f7a7c4aeb379..1fece639e900 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql @@ -404,4 +404,7 @@ UPDATE `cloud`.`configuration` SET name='denied.routes', description='Routes tha -- Rename 'master_node_count' to 'control_node_count' in kubernetes_cluster table ALTER TABLE `cloud`.`kubernetes_cluster` CHANGE master_node_count control_node_count bigint NOT NULL default '0' COMMENT 'the number of the control nodes deployed for this Kubernetes cluster'; -UPDATE `cloud`.`domain_router` SET redundant_state = 'PRIMARY' WHERE redundant_state = 'MASTER'; \ No newline at end of file +UPDATE `cloud`.`domain_router` SET redundant_state = 'PRIMARY' WHERE redundant_state = 'MASTER'; + +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listConfigurations', 'ALLOW', 303) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateConfiguration', 'ALLOW', 304) ON DUPLICATE KEY UPDATE rule=rule; diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java index e388a7539ec8..ea92133a8ddc 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -4150,6 +4150,6 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] {AllowUserViewDestroyedVM, UserVMDeniedDetails, UserVMReadOnlyDetails, SortKeyAscending, AllowUserViewAllDomainAccounts}; + return new ConfigKey[] {AllowUserViewDestroyedVM, UserVMDeniedDetails, UserVMReadOnlyDetails, SortKeyAscending, AllowUserViewAllDomainAccounts, DomainAdminAllowListedConfigurations}; } } diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index f431945c6321..11f1c44129b1 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -33,6 +33,8 @@ import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; +import java.util.stream.Collectors; +import java.util.stream.Stream; import java.util.Set; import java.util.UUID; @@ -87,6 +89,7 @@ import org.apache.cloudstack.framework.messagebus.MessageBus; import org.apache.cloudstack.framework.messagebus.MessageSubscriber; import org.apache.cloudstack.framework.messagebus.PublishScope; +import org.apache.cloudstack.query.QueryService; import org.apache.cloudstack.region.PortableIp; import org.apache.cloudstack.region.PortableIpDao; import org.apache.cloudstack.region.PortableIpRange; @@ -770,6 +773,20 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP final ConfigurationVO config = _configDao.findByName(name); String catergory = null; + final Account caller = CallContext.current().getCallingAccount(); + if (_accountMgr.isDomainAdmin(caller.getId())) { + if (domainId == null) { + throw new PermissionDeniedException("Domain admins can change only domain level configurations"); + } + + final List domainAdminWhitelistConfigs = Stream.of(QueryService.DomainAdminAllowListedConfigurations.value().split(",")) + .map(item -> (item).trim()) + .collect(Collectors.toList()); + if (!domainAdminWhitelistConfigs.contains(name)) { + throw new PermissionDeniedException("Domain admins can not change this configuration"); + } + } + // FIX ME - All configuration parameters are not moved from config.java to configKey if (config == null) { if (_configDepot.get(name) == null) { @@ -806,11 +823,14 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP paramCountCheck++; } if (accountId != null) { + Account account = _accountMgr.getAccount(accountId); + _accountMgr.checkAccess(caller, _domainDao.findById(account.getDomainId())); scope = ConfigKey.Scope.Account.toString(); id = accountId; paramCountCheck++; } if (domainId != null) { + _accountMgr.checkAccess(caller, _domainDao.findById(domainId)); scope = ConfigKey.Scope.Domain.toString(); id = domainId; paramCountCheck++; diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index 9ae7ddfd2079..2747b5f7b5aa 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -36,8 +36,8 @@ import java.util.concurrent.TimeUnit; import java.util.function.Predicate; - import java.util.stream.Collectors; +import java.util.stream.Stream; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; @@ -1953,6 +1953,11 @@ public Pair, Integer> searchForConfigurations(fina Long id = null; int paramCountCheck = 0; + final Account caller = CallContext.current().getCallingAccount(); + if (_accountMgr.isDomainAdmin(caller.getId()) && domainId == null) { + throw new PermissionDeniedException("Domain admins can view only domain level configurations"); + } + if (zoneId != null) { scope = ConfigKey.Scope.Zone.toString(); id = zoneId; @@ -1964,11 +1969,14 @@ public Pair, Integer> searchForConfigurations(fina paramCountCheck++; } if (accountId != null) { + Account account = _accountMgr.getAccount(accountId); + _accountMgr.checkAccess(caller, _domainDao.findById(account.getDomainId())); scope = ConfigKey.Scope.Account.toString(); id = accountId; paramCountCheck++; } if (domainId != null) { + _accountMgr.checkAccess(caller, _domainDao.findById(domainId)); scope = ConfigKey.Scope.Domain.toString(); id = domainId; paramCountCheck++; @@ -2018,10 +2026,21 @@ public Pair, Integer> searchForConfigurations(fina final Pair, Integer> result = _configDao.searchAndCount(sc, searchFilter); + List configs = result.first(); + + if (_accountMgr.isDomainAdmin(caller.getId())) { + final List domainAdminWhitelistConfigs = Stream.of(QueryService.DomainAdminAllowListedConfigurations.value().split(",")) + .map(item -> (item).trim()) + .collect(Collectors.toList()); + configs = configs.stream() + .filter(item -> domainAdminWhitelistConfigs.contains(item.getName())) + .collect(Collectors.toList()); + } + if (scope != null && !scope.isEmpty()) { // Populate values corresponding the resource id final List configVOList = new ArrayList(); - for (final ConfigurationVO param : result.first()) { + for (final ConfigurationVO param : configs) { final ConfigurationVO configVo = _configDao.findByName(param.getName()); if (configVo != null) { final ConfigKey key = _configDepot.get(param.getName()); @@ -2039,7 +2058,7 @@ public Pair, Integer> searchForConfigurations(fina return new Pair, Integer>(configVOList, configVOList.size()); } - return new Pair, Integer>(result.first(), result.second()); + return new Pair, Integer>(configs, result.second()); } @Override From a413b9dddbe39f2e00d620e978a98bf9e1432e1d Mon Sep 17 00:00:00 2001 From: davidjumani Date: Tue, 21 Sep 2021 15:13:52 +0530 Subject: [PATCH 2/6] Cleanup --- .../META-INF/db/schema-41510to41600.sql | 410 ------------------ 1 file changed, 410 deletions(-) delete mode 100644 engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql b/engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql deleted file mode 100644 index 1fece639e900..000000000000 --- a/engine/schema/src/main/resources/META-INF/db/schema-41510to41600.sql +++ /dev/null @@ -1,410 +0,0 @@ --- 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. - ---; --- Schema upgrade from 4.15.1.0 to 4.16.0.0 ---; - --- Adding dynamic scalable flag for service offering table -ALTER TABLE `cloud`.`service_offering` ADD COLUMN `dynamic_scaling_enabled` tinyint(1) unsigned NOT NULL DEFAULT 1 COMMENT 'true(1) if VM needs to be dynamically scalable of cpu or memory'; -DROP VIEW IF EXISTS `cloud`.`service_offering_view`; -CREATE VIEW `cloud`.`service_offering_view` AS - SELECT - `service_offering`.`id` AS `id`, - `disk_offering`.`uuid` AS `uuid`, - `disk_offering`.`name` AS `name`, - `disk_offering`.`display_text` AS `display_text`, - `disk_offering`.`provisioning_type` AS `provisioning_type`, - `disk_offering`.`created` AS `created`, - `disk_offering`.`tags` AS `tags`, - `disk_offering`.`removed` AS `removed`, - `disk_offering`.`use_local_storage` AS `use_local_storage`, - `disk_offering`.`system_use` AS `system_use`, - `disk_offering`.`customized_iops` AS `customized_iops`, - `disk_offering`.`min_iops` AS `min_iops`, - `disk_offering`.`max_iops` AS `max_iops`, - `disk_offering`.`hv_ss_reserve` AS `hv_ss_reserve`, - `disk_offering`.`bytes_read_rate` AS `bytes_read_rate`, - `disk_offering`.`bytes_read_rate_max` AS `bytes_read_rate_max`, - `disk_offering`.`bytes_read_rate_max_length` AS `bytes_read_rate_max_length`, - `disk_offering`.`bytes_write_rate` AS `bytes_write_rate`, - `disk_offering`.`bytes_write_rate_max` AS `bytes_write_rate_max`, - `disk_offering`.`bytes_write_rate_max_length` AS `bytes_write_rate_max_length`, - `disk_offering`.`iops_read_rate` AS `iops_read_rate`, - `disk_offering`.`iops_read_rate_max` AS `iops_read_rate_max`, - `disk_offering`.`iops_read_rate_max_length` AS `iops_read_rate_max_length`, - `disk_offering`.`iops_write_rate` AS `iops_write_rate`, - `disk_offering`.`iops_write_rate_max` AS `iops_write_rate_max`, - `disk_offering`.`iops_write_rate_max_length` AS `iops_write_rate_max_length`, - `disk_offering`.`cache_mode` AS `cache_mode`, - `disk_offering`.`disk_size` AS `root_disk_size`, - `service_offering`.`cpu` AS `cpu`, - `service_offering`.`speed` AS `speed`, - `service_offering`.`ram_size` AS `ram_size`, - `service_offering`.`nw_rate` AS `nw_rate`, - `service_offering`.`mc_rate` AS `mc_rate`, - `service_offering`.`ha_enabled` AS `ha_enabled`, - `service_offering`.`limit_cpu_use` AS `limit_cpu_use`, - `service_offering`.`host_tag` AS `host_tag`, - `service_offering`.`default_use` AS `default_use`, - `service_offering`.`vm_type` AS `vm_type`, - `service_offering`.`sort_key` AS `sort_key`, - `service_offering`.`is_volatile` AS `is_volatile`, - `service_offering`.`deployment_planner` AS `deployment_planner`, - `service_offering`.`dynamic_scaling_enabled` AS `dynamic_scaling_enabled`, - `vsphere_storage_policy`.`value` AS `vsphere_storage_policy`, - GROUP_CONCAT(DISTINCT(domain.id)) AS domain_id, - GROUP_CONCAT(DISTINCT(domain.uuid)) AS domain_uuid, - GROUP_CONCAT(DISTINCT(domain.name)) AS domain_name, - GROUP_CONCAT(DISTINCT(domain.path)) AS domain_path, - GROUP_CONCAT(DISTINCT(zone.id)) AS zone_id, - GROUP_CONCAT(DISTINCT(zone.uuid)) AS zone_uuid, - GROUP_CONCAT(DISTINCT(zone.name)) AS zone_name, - IFNULL(`min_compute_details`.`value`, `cpu`) AS min_cpu, - IFNULL(`max_compute_details`.`value`, `cpu`) AS max_cpu, - IFNULL(`min_memory_details`.`value`, `ram_size`) AS min_memory, - IFNULL(`max_memory_details`.`value`, `ram_size`) AS max_memory - FROM - `cloud`.`service_offering` - INNER JOIN - `cloud`.`disk_offering_view` AS `disk_offering` ON service_offering.id = disk_offering.id - LEFT JOIN - `cloud`.`service_offering_details` AS `domain_details` ON `domain_details`.`service_offering_id` = `disk_offering`.`id` AND `domain_details`.`name`='domainid' - LEFT JOIN - `cloud`.`domain` AS `domain` ON FIND_IN_SET(`domain`.`id`, `domain_details`.`value`) - LEFT JOIN - `cloud`.`service_offering_details` AS `zone_details` ON `zone_details`.`service_offering_id` = `disk_offering`.`id` AND `zone_details`.`name`='zoneid' - LEFT JOIN - `cloud`.`data_center` AS `zone` ON FIND_IN_SET(`zone`.`id`, `zone_details`.`value`) - LEFT JOIN - `cloud`.`service_offering_details` AS `min_compute_details` ON `min_compute_details`.`service_offering_id` = `disk_offering`.`id` - AND `min_compute_details`.`name` = 'mincpunumber' - LEFT JOIN - `cloud`.`service_offering_details` AS `max_compute_details` ON `max_compute_details`.`service_offering_id` = `disk_offering`.`id` - AND `max_compute_details`.`name` = 'maxcpunumber' - LEFT JOIN - `cloud`.`service_offering_details` AS `min_memory_details` ON `min_memory_details`.`service_offering_id` = `disk_offering`.`id` - AND `min_memory_details`.`name` = 'minmemory' - LEFT JOIN - `cloud`.`service_offering_details` AS `max_memory_details` ON `max_memory_details`.`service_offering_id` = `disk_offering`.`id` - AND `max_memory_details`.`name` = 'maxmemory' - LEFT JOIN - `cloud`.`service_offering_details` AS `vsphere_storage_policy` ON `vsphere_storage_policy`.`service_offering_id` = `disk_offering`.`id` - AND `vsphere_storage_policy`.`name` = 'storagepolicy' - WHERE - `disk_offering`.`state`='Active' - GROUP BY - `service_offering`.`id`; - ---; --- Stored procedure to do idempotent column add; --- This is copied from schema-41000to41100.sql ---; -DROP PROCEDURE IF EXISTS `cloud`.`IDEMPOTENT_ADD_COLUMN`; - -CREATE PROCEDURE `cloud`.`IDEMPOTENT_ADD_COLUMN` ( - IN in_table_name VARCHAR(200), - IN in_column_name VARCHAR(200), - IN in_column_definition VARCHAR(1000) -) -BEGIN - - DECLARE CONTINUE HANDLER FOR 1060 BEGIN END; SET @ddl = CONCAT('ALTER TABLE ', in_table_name); SET @ddl = CONCAT(@ddl, ' ', 'ADD COLUMN') ; SET @ddl = CONCAT(@ddl, ' ', in_column_name); SET @ddl = CONCAT(@ddl, ' ', in_column_definition); PREPARE stmt FROM @ddl; EXECUTE stmt; DEALLOCATE PREPARE stmt; END; - -CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.account','created', 'datetime DEFAULT NULL COMMENT ''date created'' AFTER `state` '); -CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud.domain','created', 'datetime DEFAULT NULL COMMENT ''date created'' AFTER `next_child_seq` '); -CALL `cloud`.`IDEMPOTENT_ADD_COLUMN`('cloud_usage.account','created', 'datetime DEFAULT NULL COMMENT ''date created'' AFTER `state` '); - -DROP VIEW IF EXISTS `cloud`.`account_view`; -CREATE VIEW `cloud`.`account_view` AS -select - `account`.`id` AS `id`, - `account`.`uuid` AS `uuid`, - `account`.`account_name` AS `account_name`, - `account`.`type` AS `type`, - `account`.`role_id` AS `role_id`, - `account`.`state` AS `state`, - `account`.`created` AS `created`, - `account`.`removed` AS `removed`, - `account`.`cleanup_needed` AS `cleanup_needed`, - `account`.`network_domain` AS `network_domain` , - `account`.`default` AS `default`, - `domain`.`id` AS `domain_id`, - `domain`.`uuid` AS `domain_uuid`, - `domain`.`name` AS `domain_name`, - `domain`.`path` AS `domain_path`, - `data_center`.`id` AS `data_center_id`, - `data_center`.`uuid` AS `data_center_uuid`, - `data_center`.`name` AS `data_center_name`, - `account_netstats_view`.`bytesReceived` AS `bytesReceived`, - `account_netstats_view`.`bytesSent` AS `bytesSent`, - `vmlimit`.`max` AS `vmLimit`, - `vmcount`.`count` AS `vmTotal`, - `runningvm`.`vmcount` AS `runningVms`, - `stoppedvm`.`vmcount` AS `stoppedVms`, - `iplimit`.`max` AS `ipLimit`, - `ipcount`.`count` AS `ipTotal`, - `free_ip_view`.`free_ip` AS `ipFree`, - `volumelimit`.`max` AS `volumeLimit`, - `volumecount`.`count` AS `volumeTotal`, - `snapshotlimit`.`max` AS `snapshotLimit`, - `snapshotcount`.`count` AS `snapshotTotal`, - `templatelimit`.`max` AS `templateLimit`, - `templatecount`.`count` AS `templateTotal`, - `vpclimit`.`max` AS `vpcLimit`, - `vpccount`.`count` AS `vpcTotal`, - `projectlimit`.`max` AS `projectLimit`, - `projectcount`.`count` AS `projectTotal`, - `networklimit`.`max` AS `networkLimit`, - `networkcount`.`count` AS `networkTotal`, - `cpulimit`.`max` AS `cpuLimit`, - `cpucount`.`count` AS `cpuTotal`, - `memorylimit`.`max` AS `memoryLimit`, - `memorycount`.`count` AS `memoryTotal`, - `primary_storage_limit`.`max` AS `primaryStorageLimit`, - `primary_storage_count`.`count` AS `primaryStorageTotal`, - `secondary_storage_limit`.`max` AS `secondaryStorageLimit`, - `secondary_storage_count`.`count` AS `secondaryStorageTotal`, - `async_job`.`id` AS `job_id`, - `async_job`.`uuid` AS `job_uuid`, - `async_job`.`job_status` AS `job_status`, - `async_job`.`account_id` AS `job_account_id` -from - `cloud`.`free_ip_view`, - `cloud`.`account` - inner join - `cloud`.`domain` ON account.domain_id = domain.id - left join - `cloud`.`data_center` ON account.default_zone_id = data_center.id - left join - `cloud`.`account_netstats_view` ON account.id = account_netstats_view.account_id - left join - `cloud`.`resource_limit` vmlimit ON account.id = vmlimit.account_id - and vmlimit.type = 'user_vm' - left join - `cloud`.`resource_count` vmcount ON account.id = vmcount.account_id - and vmcount.type = 'user_vm' - left join - `cloud`.`account_vmstats_view` runningvm ON account.id = runningvm.account_id - and runningvm.state = 'Running' - left join - `cloud`.`account_vmstats_view` stoppedvm ON account.id = stoppedvm.account_id - and stoppedvm.state = 'Stopped' - left join - `cloud`.`resource_limit` iplimit ON account.id = iplimit.account_id - and iplimit.type = 'public_ip' - left join - `cloud`.`resource_count` ipcount ON account.id = ipcount.account_id - and ipcount.type = 'public_ip' - left join - `cloud`.`resource_limit` volumelimit ON account.id = volumelimit.account_id - and volumelimit.type = 'volume' - left join - `cloud`.`resource_count` volumecount ON account.id = volumecount.account_id - and volumecount.type = 'volume' - left join - `cloud`.`resource_limit` snapshotlimit ON account.id = snapshotlimit.account_id - and snapshotlimit.type = 'snapshot' - left join - `cloud`.`resource_count` snapshotcount ON account.id = snapshotcount.account_id - and snapshotcount.type = 'snapshot' - left join - `cloud`.`resource_limit` templatelimit ON account.id = templatelimit.account_id - and templatelimit.type = 'template' - left join - `cloud`.`resource_count` templatecount ON account.id = templatecount.account_id - and templatecount.type = 'template' - left join - `cloud`.`resource_limit` vpclimit ON account.id = vpclimit.account_id - and vpclimit.type = 'vpc' - left join - `cloud`.`resource_count` vpccount ON account.id = vpccount.account_id - and vpccount.type = 'vpc' - left join - `cloud`.`resource_limit` projectlimit ON account.id = projectlimit.account_id - and projectlimit.type = 'project' - left join - `cloud`.`resource_count` projectcount ON account.id = projectcount.account_id - and projectcount.type = 'project' - left join - `cloud`.`resource_limit` networklimit ON account.id = networklimit.account_id - and networklimit.type = 'network' - left join - `cloud`.`resource_count` networkcount ON account.id = networkcount.account_id - and networkcount.type = 'network' - left join - `cloud`.`resource_limit` cpulimit ON account.id = cpulimit.account_id - and cpulimit.type = 'cpu' - left join - `cloud`.`resource_count` cpucount ON account.id = cpucount.account_id - and cpucount.type = 'cpu' - left join - `cloud`.`resource_limit` memorylimit ON account.id = memorylimit.account_id - and memorylimit.type = 'memory' - left join - `cloud`.`resource_count` memorycount ON account.id = memorycount.account_id - and memorycount.type = 'memory' - left join - `cloud`.`resource_limit` primary_storage_limit ON account.id = primary_storage_limit.account_id - and primary_storage_limit.type = 'primary_storage' - left join - `cloud`.`resource_count` primary_storage_count ON account.id = primary_storage_count.account_id - and primary_storage_count.type = 'primary_storage' - left join - `cloud`.`resource_limit` secondary_storage_limit ON account.id = secondary_storage_limit.account_id - and secondary_storage_limit.type = 'secondary_storage' - left join - `cloud`.`resource_count` secondary_storage_count ON account.id = secondary_storage_count.account_id - and secondary_storage_count.type = 'secondary_storage' - left join - `cloud`.`async_job` ON async_job.instance_id = account.id - and async_job.instance_type = 'Account' - and async_job.job_status = 0; - - -DROP VIEW IF EXISTS `cloud`.`domain_view`; -CREATE VIEW `cloud`.`domain_view` AS -select - `domain`.`id` AS `id`, - `domain`.`parent` AS `parent`, - `domain`.`name` AS `name`, - `domain`.`uuid` AS `uuid`, - `domain`.`owner` AS `owner`, - `domain`.`path` AS `path`, - `domain`.`level` AS `level`, - `domain`.`child_count` AS `child_count`, - `domain`.`next_child_seq` AS `next_child_seq`, - `domain`.`created` AS `created`, - `domain`.`removed` AS `removed`, - `domain`.`state` AS `state`, - `domain`.`network_domain` AS `network_domain`, - `domain`.`type` AS `type`, - `vmlimit`.`max` AS `vmLimit`, - `vmcount`.`count` AS `vmTotal`, - `iplimit`.`max` AS `ipLimit`, - `ipcount`.`count` AS `ipTotal`, - `volumelimit`.`max` AS `volumeLimit`, - `volumecount`.`count` AS `volumeTotal`, - `snapshotlimit`.`max` AS `snapshotLimit`, - `snapshotcount`.`count` AS `snapshotTotal`, - `templatelimit`.`max` AS `templateLimit`, - `templatecount`.`count` AS `templateTotal`, - `vpclimit`.`max` AS `vpcLimit`, - `vpccount`.`count` AS `vpcTotal`, - `projectlimit`.`max` AS `projectLimit`, - `projectcount`.`count` AS `projectTotal`, - `networklimit`.`max` AS `networkLimit`, - `networkcount`.`count` AS `networkTotal`, - `cpulimit`.`max` AS `cpuLimit`, - `cpucount`.`count` AS `cpuTotal`, - `memorylimit`.`max` AS `memoryLimit`, - `memorycount`.`count` AS `memoryTotal`, - `primary_storage_limit`.`max` AS `primaryStorageLimit`, - `primary_storage_count`.`count` AS `primaryStorageTotal`, - `secondary_storage_limit`.`max` AS `secondaryStorageLimit`, - `secondary_storage_count`.`count` AS `secondaryStorageTotal` -from - `cloud`.`domain` - left join - `cloud`.`resource_limit` vmlimit ON domain.id = vmlimit.domain_id - and vmlimit.type = 'user_vm' - left join - `cloud`.`resource_count` vmcount ON domain.id = vmcount.domain_id - and vmcount.type = 'user_vm' - left join - `cloud`.`resource_limit` iplimit ON domain.id = iplimit.domain_id - and iplimit.type = 'public_ip' - left join - `cloud`.`resource_count` ipcount ON domain.id = ipcount.domain_id - and ipcount.type = 'public_ip' - left join - `cloud`.`resource_limit` volumelimit ON domain.id = volumelimit.domain_id - and volumelimit.type = 'volume' - left join - `cloud`.`resource_count` volumecount ON domain.id = volumecount.domain_id - and volumecount.type = 'volume' - left join - `cloud`.`resource_limit` snapshotlimit ON domain.id = snapshotlimit.domain_id - and snapshotlimit.type = 'snapshot' - left join - `cloud`.`resource_count` snapshotcount ON domain.id = snapshotcount.domain_id - and snapshotcount.type = 'snapshot' - left join - `cloud`.`resource_limit` templatelimit ON domain.id = templatelimit.domain_id - and templatelimit.type = 'template' - left join - `cloud`.`resource_count` templatecount ON domain.id = templatecount.domain_id - and templatecount.type = 'template' - left join - `cloud`.`resource_limit` vpclimit ON domain.id = vpclimit.domain_id - and vpclimit.type = 'vpc' - left join - `cloud`.`resource_count` vpccount ON domain.id = vpccount.domain_id - and vpccount.type = 'vpc' - left join - `cloud`.`resource_limit` projectlimit ON domain.id = projectlimit.domain_id - and projectlimit.type = 'project' - left join - `cloud`.`resource_count` projectcount ON domain.id = projectcount.domain_id - and projectcount.type = 'project' - left join - `cloud`.`resource_limit` networklimit ON domain.id = networklimit.domain_id - and networklimit.type = 'network' - left join - `cloud`.`resource_count` networkcount ON domain.id = networkcount.domain_id - and networkcount.type = 'network' - left join - `cloud`.`resource_limit` cpulimit ON domain.id = cpulimit.domain_id - and cpulimit.type = 'cpu' - left join - `cloud`.`resource_count` cpucount ON domain.id = cpucount.domain_id - and cpucount.type = 'cpu' - left join - `cloud`.`resource_limit` memorylimit ON domain.id = memorylimit.domain_id - and memorylimit.type = 'memory' - left join - `cloud`.`resource_count` memorycount ON domain.id = memorycount.domain_id - and memorycount.type = 'memory' - left join - `cloud`.`resource_limit` primary_storage_limit ON domain.id = primary_storage_limit.domain_id - and primary_storage_limit.type = 'primary_storage' - left join - `cloud`.`resource_count` primary_storage_count ON domain.id = primary_storage_count.domain_id - and primary_storage_count.type = 'primary_storage' - left join - `cloud`.`resource_limit` secondary_storage_limit ON domain.id = secondary_storage_limit.domain_id - and secondary_storage_limit.type = 'secondary_storage' - left join - `cloud`.`resource_count` secondary_storage_count ON domain.id = secondary_storage_count.domain_id - and secondary_storage_count.type = 'secondary_storage'; - --- Update name for global configuration user.vm.readonly.ui.details -Update configuration set name='user.vm.readonly.details' where name='user.vm.readonly.ui.details'; - --- Update name for global configuration 'user.vm.readonly.ui.details' to 'user.vm.denied.details' -UPDATE `cloud`.`configuration` SET name='user.vm.denied.details' WHERE name='user.vm.blacklisted.details'; - --- Update name for global configuration 'blacklisted.routes' to 'denied.routes' -UPDATE `cloud`.`configuration` SET name='denied.routes', description='Routes that are denied, can not be used for Static Routes creation for the VPC Private Gateway' WHERE name='blacklisted.routes'; - --- Rename 'master_node_count' to 'control_node_count' in kubernetes_cluster table -ALTER TABLE `cloud`.`kubernetes_cluster` CHANGE master_node_count control_node_count bigint NOT NULL default '0' COMMENT 'the number of the control nodes deployed for this Kubernetes cluster'; - -UPDATE `cloud`.`domain_router` SET redundant_state = 'PRIMARY' WHERE redundant_state = 'MASTER'; - -INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listConfigurations', 'ALLOW', 303) ON DUPLICATE KEY UPDATE rule=rule; -INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateConfiguration', 'ALLOW', 304) ON DUPLICATE KEY UPDATE rule=rule; From 5c6075c08510e33b0f6c5ea9b3a2332d1c614d50 Mon Sep 17 00:00:00 2001 From: davidjumani Date: Tue, 21 Sep 2021 16:30:28 +0530 Subject: [PATCH 3/6] Remove useless global setting --- .../apache/cloudstack/query/QueryService.java | 3 --- .../com/cloud/api/query/QueryManagerImpl.java | 2 +- .../ConfigurationManagerImpl.java | 15 +++--------- .../cloud/server/ManagementServerImpl.java | 24 ++++++------------- ui/src/config/section/account.js | 2 +- ui/src/config/section/config.js | 2 +- ui/src/config/section/domain.js | 2 +- 7 files changed, 14 insertions(+), 36 deletions(-) diff --git a/api/src/main/java/org/apache/cloudstack/query/QueryService.java b/api/src/main/java/org/apache/cloudstack/query/QueryService.java index bb628fdfe6e4..bb418f98408f 100644 --- a/api/src/main/java/org/apache/cloudstack/query/QueryService.java +++ b/api/src/main/java/org/apache/cloudstack/query/QueryService.java @@ -98,9 +98,6 @@ public interface QueryService { "user.vm.denied.details", "rootdisksize, cpuOvercommitRatio, memoryOvercommitRatio, Message.ReservedCapacityFreed.Flag", "Determines whether users can view certain VM settings. When set to empty, default value used is: rootdisksize, cpuOvercommitRatio, memoryOvercommitRatio, Message.ReservedCapacityFreed.Flag.", true); - static final ConfigKey DomainAdminAllowListedConfigurations = new ConfigKey("Advanced", String.class, - "domain.admin.allowlisted.config", "", "Determines which domain and account level configurations the domain admin is able to change", true); - static final ConfigKey UserVMReadOnlyDetails = new ConfigKey("Advanced", String.class, "user.vm.readonly.details", "dataDiskController, rootDiskController", "List of read-only VM settings/details as comma separated string", true); diff --git a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java index fb91a978394f..7c5a4864b3ef 100644 --- a/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java +++ b/server/src/main/java/com/cloud/api/query/QueryManagerImpl.java @@ -4260,6 +4260,6 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] {AllowUserViewDestroyedVM, UserVMDeniedDetails, UserVMReadOnlyDetails, SortKeyAscending, AllowUserViewAllDomainAccounts, DomainAdminAllowListedConfigurations}; + return new ConfigKey[] {AllowUserViewDestroyedVM, UserVMDeniedDetails, UserVMReadOnlyDetails, SortKeyAscending, AllowUserViewAllDomainAccounts}; } } diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index f63b911b696c..df63e147dbf3 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -34,8 +34,6 @@ import java.util.ListIterator; import java.util.Map; import java.util.Map.Entry; -import java.util.stream.Collectors; -import java.util.stream.Stream; import java.util.Set; import java.util.UUID; import java.util.Vector; @@ -802,7 +800,7 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP final Long storagepoolId = cmd.getStoragepoolId(); final Long accountId = cmd.getAccountId(); final Long imageStoreId = cmd.getImageStoreId(); - final Long domainId = cmd.getDomainId(); + Long domainId = cmd.getDomainId(); CallContext.current().setEventDetails(" Name: " + name + " New Value: " + (name.toLowerCase().contains("password") ? "*****" : value == null ? "" : value)); // check if config value exists final ConfigurationVO config = _configDao.findByName(name); @@ -810,15 +808,8 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP final Account caller = CallContext.current().getCallingAccount(); if (_accountMgr.isDomainAdmin(caller.getId())) { - if (domainId == null) { - throw new PermissionDeniedException("Domain admins can change only domain level configurations"); - } - - final List domainAdminWhitelistConfigs = Stream.of(QueryService.DomainAdminAllowListedConfigurations.value().split(",")) - .map(item -> (item).trim()) - .collect(Collectors.toList()); - if (!domainAdminWhitelistConfigs.contains(name)) { - throw new PermissionDeniedException("Domain admins can not change this configuration"); + if (accountId == null && domainId == null) { + domainId = caller.getDomainId(); } } diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index 90674d843ad2..77d8564385d9 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -37,7 +37,6 @@ import java.util.function.Predicate; import java.util.stream.Collectors; -import java.util.stream.Stream; import javax.crypto.Mac; import javax.crypto.spec.SecretKeySpec; @@ -1975,15 +1974,17 @@ public Pair, Integer> searchForConfigurations(fina final Long clusterId = cmd.getClusterId(); final Long storagepoolId = cmd.getStoragepoolId(); final Long accountId = cmd.getAccountId(); - final Long domainId = cmd.getDomainId(); final Long imageStoreId = cmd.getImageStoreId(); + Long domainId = cmd.getDomainId(); String scope = null; Long id = null; int paramCountCheck = 0; final Account caller = CallContext.current().getCallingAccount(); - if (_accountMgr.isDomainAdmin(caller.getId()) && domainId == null) { - throw new PermissionDeniedException("Domain admins can view only domain level configurations"); + if (_accountMgr.isDomainAdmin(caller.getId())) { + if (accountId == null && domainId == null) { + domainId = caller.getDomainId(); + } } if (zoneId != null) { @@ -2054,21 +2055,10 @@ public Pair, Integer> searchForConfigurations(fina final Pair, Integer> result = _configDao.searchAndCount(sc, searchFilter); - List configs = result.first(); - - if (_accountMgr.isDomainAdmin(caller.getId())) { - final List domainAdminWhitelistConfigs = Stream.of(QueryService.DomainAdminAllowListedConfigurations.value().split(",")) - .map(item -> (item).trim()) - .collect(Collectors.toList()); - configs = configs.stream() - .filter(item -> domainAdminWhitelistConfigs.contains(item.getName())) - .collect(Collectors.toList()); - } - if (scope != null && !scope.isEmpty()) { // Populate values corresponding the resource id final List configVOList = new ArrayList(); - for (final ConfigurationVO param : configs) { + for (final ConfigurationVO param : result.first()) { final ConfigurationVO configVo = _configDao.findByName(param.getName()); if (configVo != null) { final ConfigKey key = _configDepot.get(param.getName()); @@ -2086,7 +2076,7 @@ public Pair, Integer> searchForConfigurations(fina return new Pair, Integer>(configVOList, configVOList.size()); } - return new Pair, Integer>(configs, result.second()); + return new Pair, Integer>(result.first(), result.second()); } @Override diff --git a/ui/src/config/section/account.js b/ui/src/config/section/account.js index 1b919035e0f4..9803e8bd1e45 100644 --- a/ui/src/config/section/account.js +++ b/ui/src/config/section/account.js @@ -49,7 +49,7 @@ export default { { name: 'settings', component: () => import('@/components/view/SettingsTab.vue'), - show: (record, route, user) => { return ['Admin'].includes(user.roletype) } + show: (record, route, user) => { return ['Admin', 'DomainAdmin'].includes(user.roletype) } } ], actions: [ diff --git a/ui/src/config/section/config.js b/ui/src/config/section/config.js index 8b77c65d4113..bb8ae2838976 100644 --- a/ui/src/config/section/config.js +++ b/ui/src/config/section/config.js @@ -19,7 +19,7 @@ export default { name: 'config', title: 'label.configuration', icon: 'setting', - permission: ['listConfigurations'], + permission: ['listConfigurations', 'listInfrastructure'], children: [ { name: 'globalsetting', diff --git a/ui/src/config/section/domain.js b/ui/src/config/section/domain.js index 7575202a6426..b2d45ee58a28 100644 --- a/ui/src/config/section/domain.js +++ b/ui/src/config/section/domain.js @@ -53,7 +53,7 @@ export default { { name: 'settings', component: () => import('@/components/view/SettingsTab.vue'), - show: (record, route, user) => { return ['Admin'].includes(user.roletype) } + show: (record, route, user) => { return ['Admin', 'DomainAdmin'].includes(user.roletype) } }, { name: 'comments', component: () => import('@/components/view/AnnotationsTab.vue') From 3cef3d5c8314a050406c225ef2281f628a613057 Mon Sep 17 00:00:00 2001 From: davidjumani Date: Wed, 29 Sep 2021 17:27:23 +0530 Subject: [PATCH 4/6] Restrict regular users with listConfig access --- .../com/cloud/configuration/ConfigurationManagerImpl.java | 8 ++++++-- .../main/java/com/cloud/server/ManagementServerImpl.java | 8 ++++++-- ui/src/config/section/account.js | 4 +++- ui/src/config/section/domain.js | 4 +++- 4 files changed, 18 insertions(+), 6 deletions(-) diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index df63e147dbf3..d2535642d4fa 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -798,8 +798,8 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP final Long zoneId = cmd.getZoneId(); final Long clusterId = cmd.getClusterId(); final Long storagepoolId = cmd.getStoragepoolId(); - final Long accountId = cmd.getAccountId(); final Long imageStoreId = cmd.getImageStoreId(); + Long accountId = cmd.getAccountId(); Long domainId = cmd.getDomainId(); CallContext.current().setEventDetails(" Name: " + name + " New Value: " + (name.toLowerCase().contains("password") ? "*****" : value == null ? "" : value)); // check if config value exists @@ -811,6 +811,10 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP if (accountId == null && domainId == null) { domainId = caller.getDomainId(); } + } else if (_accountMgr.isNormalUser(caller.getId())) { + if (accountId == null) { + accountId = caller.getAccountId(); + } } // FIX ME - All configuration parameters are not moved from config.java to configKey @@ -850,7 +854,7 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP } if (accountId != null) { Account account = _accountMgr.getAccount(accountId); - _accountMgr.checkAccess(caller, _domainDao.findById(account.getDomainId())); + _accountMgr.checkAccess(caller, null, true, account); scope = ConfigKey.Scope.Account.toString(); id = accountId; paramCountCheck++; diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index 77d8564385d9..b1827ec0f121 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -1973,8 +1973,8 @@ public Pair, Integer> searchForConfigurations(fina final Long zoneId = cmd.getZoneId(); final Long clusterId = cmd.getClusterId(); final Long storagepoolId = cmd.getStoragepoolId(); - final Long accountId = cmd.getAccountId(); final Long imageStoreId = cmd.getImageStoreId(); + Long accountId = cmd.getAccountId(); Long domainId = cmd.getDomainId(); String scope = null; Long id = null; @@ -1985,6 +1985,10 @@ public Pair, Integer> searchForConfigurations(fina if (accountId == null && domainId == null) { domainId = caller.getDomainId(); } + } else if (_accountMgr.isNormalUser(caller.getId())) { + if (accountId == null) { + accountId = caller.getAccountId(); + } } if (zoneId != null) { @@ -1999,7 +2003,7 @@ public Pair, Integer> searchForConfigurations(fina } if (accountId != null) { Account account = _accountMgr.getAccount(accountId); - _accountMgr.checkAccess(caller, _domainDao.findById(account.getDomainId())); + _accountMgr.checkAccess(caller, null, true, account); scope = ConfigKey.Scope.Account.toString(); id = accountId; paramCountCheck++; diff --git a/ui/src/config/section/account.js b/ui/src/config/section/account.js index 9803e8bd1e45..a9547ab86859 100644 --- a/ui/src/config/section/account.js +++ b/ui/src/config/section/account.js @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +import store from '@/store' + export default { name: 'account', title: 'label.accounts', @@ -49,7 +51,7 @@ export default { { name: 'settings', component: () => import('@/components/view/SettingsTab.vue'), - show: (record, route, user) => { return ['Admin', 'DomainAdmin'].includes(user.roletype) } + show: () => { return 'listConfigurations' in store.getters.apis } } ], actions: [ diff --git a/ui/src/config/section/domain.js b/ui/src/config/section/domain.js index b2d45ee58a28..63dd94f273ad 100644 --- a/ui/src/config/section/domain.js +++ b/ui/src/config/section/domain.js @@ -15,6 +15,8 @@ // specific language governing permissions and limitations // under the License. +import store from '@/store' + export default { name: 'domain', title: 'label.domains', @@ -53,7 +55,7 @@ export default { { name: 'settings', component: () => import('@/components/view/SettingsTab.vue'), - show: (record, route, user) => { return ['Admin', 'DomainAdmin'].includes(user.roletype) } + show: () => { return 'listConfigurations' in store.getters.apis } }, { name: 'comments', component: () => import('@/components/view/AnnotationsTab.vue') From d3a574df591d1ca5497cef32418a2ba2ca9ae439 Mon Sep 17 00:00:00 2001 From: davidjumani Date: Thu, 30 Sep 2021 09:39:00 +0530 Subject: [PATCH 5/6] Address comments --- .../java/com/cloud/configuration/ConfigurationManagerImpl.java | 2 +- server/src/main/java/com/cloud/server/ManagementServerImpl.java | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java index d2535642d4fa..618a63aef1db 100755 --- a/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java @@ -854,7 +854,7 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP } if (accountId != null) { Account account = _accountMgr.getAccount(accountId); - _accountMgr.checkAccess(caller, null, true, account); + _accountMgr.checkAccess(caller, null, false, account); scope = ConfigKey.Scope.Account.toString(); id = accountId; paramCountCheck++; diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index b1827ec0f121..fd31f8467e1e 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -2003,7 +2003,7 @@ public Pair, Integer> searchForConfigurations(fina } if (accountId != null) { Account account = _accountMgr.getAccount(accountId); - _accountMgr.checkAccess(caller, null, true, account); + _accountMgr.checkAccess(caller, null, false, account); scope = ConfigKey.Scope.Account.toString(); id = accountId; paramCountCheck++; From 6bbbcc3e1bf669d8750093d7bb8f040acbb20bd8 Mon Sep 17 00:00:00 2001 From: davidjumani Date: Tue, 15 Feb 2022 17:13:36 +0530 Subject: [PATCH 6/6] Moving upgrade path --- .../src/main/resources/META-INF/db/schema-41520to41600.sql | 3 --- .../src/main/resources/META-INF/db/schema-41610to41700.sql | 3 +++ 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41520to41600.sql b/engine/schema/src/main/resources/META-INF/db/schema-41520to41600.sql index 7b90b4c3d680..a414f244b089 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41520to41600.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41520to41600.sql @@ -794,6 +794,3 @@ ALTER TABLE cloud.user_vm_details MODIFY value varchar(5120) NOT NULL; ALTER TABLE cloud_usage.usage_network DROP PRIMARY KEY, ADD PRIMARY KEY (`account_id`,`zone_id`,`host_id`,`network_id`,`event_time_millis`); ALTER TABLE `cloud`.`user_statistics` DROP INDEX `account_id`, ADD UNIQUE KEY `account_id` (`account_id`,`data_center_id`,`public_ip_address`,`device_id`,`device_type`, `network_id`); ALTER TABLE `cloud_usage`.`user_statistics` DROP INDEX `account_id`, ADD UNIQUE KEY `account_id` (`account_id`,`data_center_id`,`public_ip_address`,`device_id`,`device_type`, `network_id`); - -INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'listConfigurations', 'ALLOW', 303) ON DUPLICATE KEY UPDATE rule=rule; -INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) values (UUID(), 3, 'updateConfiguration', 'ALLOW', 304) ON DUPLICATE KEY UPDATE rule=rule; diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql index 822cf00e630b..1eeb2087cebc 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41610to41700.sql @@ -643,3 +643,6 @@ CREATE VIEW `cloud`.`domain_router_view` AS `cloud`.`async_job` ON async_job.instance_id = vm_instance.id and async_job.instance_type = 'DomainRouter' and async_job.job_status = 0; + +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) SELECT UUID(), 3, 'listConfigurations', 'ALLOW', (SELECT MAX(`sort_order`)+1 FROM `cloud`.`role_permissions`) ON DUPLICATE KEY UPDATE rule=rule; +INSERT INTO `cloud`.`role_permissions` (`uuid`, `role_id`, `rule`, `permission`, `sort_order`) SELECT UUID(), 3, 'updateConfiguration', 'ALLOW', (SELECT MAX(`sort_order`)+1 FROM `cloud`.`role_permissions`) ON DUPLICATE KEY UPDATE rule=rule;