Skip to content

Commit d944af5

Browse files
shwstpprdhslove
authored andcommitted
server,utils: improve js interpretation functionality
Make JS interpretation functionalities configurable via a hidden config - js.interpretation.enabled Default value is false, making such functionalities disabled, ie, new heuristic rules cannot be added or updated. For JsInterpretor, use --no-java --no-syntax-extensions args and a deny-all ClassFilter. Replace string-spliced vars with ENGINE_SCOPE Bindings, use a fresh ScriptContext per run, and compile before eval. Use a named daemon worker with hard timeouts and capture stdout. Signed-off-by: Abhishek Kumar <[email protected]>
1 parent 21d03bb commit d944af5

File tree

12 files changed

+253
-114
lines changed

12 files changed

+253
-114
lines changed

api/src/main/java/com/cloud/server/ManagementService.java

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@
2020
import java.util.List;
2121
import java.util.Map;
2222

23-
import com.cloud.user.UserData;
2423
import org.apache.cloudstack.api.command.admin.cluster.ListClustersCmd;
2524
import org.apache.cloudstack.api.command.admin.config.ListCfgGroupsByCmd;
2625
import org.apache.cloudstack.api.command.admin.config.ListCfgsByCmd;
@@ -88,6 +87,7 @@
8887
// import org.apache.cloudstack.api.response.UpdateHostUsbDevicesResponse;
8988
import org.apache.cloudstack.config.Configuration;
9089
import org.apache.cloudstack.config.ConfigurationGroup;
90+
import org.apache.cloudstack.framework.config.ConfigKey;
9191

9292
import com.cloud.alert.Alert;
9393
import com.cloud.capacity.Capacity;
@@ -107,6 +107,7 @@
107107
import com.cloud.storage.GuestOsCategory;
108108
import com.cloud.storage.StoragePool;
109109
import com.cloud.user.SSHKeyPair;
110+
import com.cloud.user.UserData;
110111
import com.cloud.utils.Pair;
111112
import com.cloud.utils.Ternary;
112113
import com.cloud.vm.InstanceGroup;
@@ -121,6 +122,14 @@
121122
public interface ManagementService {
122123
static final String Name = "management-server";
123124

125+
ConfigKey<Boolean> JsInterpretationEnabled = new ConfigKey<>("Hidden"
126+
, Boolean.class
127+
, "js.interpretation.enabled"
128+
, "false"
129+
, "Enable/Disable all JavaScript interpretation related functionalities to create or update Javascript rules."
130+
, false
131+
, ConfigKey.Scope.Global);
132+
124133
/**
125134
* returns the a map of the names/values in the configuration table
126135
*
@@ -545,7 +554,8 @@ VirtualMachine upgradeSystemVM(ScaleSystemVMCmd cmd) throws ResourceUnavailableE
545554

546555
LicenseCheckerResponse checkLicense(LicenseCheckCmd cmd);
547556

548-
549557
boolean removeManagementServer(RemoveManagementServerCmd cmd);
558+
559+
void checkJsInterpretationAllowedIfNeededForParameterValue(String paramName, boolean paramValue);
550560

551561
}

framework/quota/src/main/java/org/apache/cloudstack/quota/QuotaManagerImpl.java

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@
3232
import javax.inject.Inject;
3333
import javax.naming.ConfigurationException;
3434

35-
import com.cloud.user.Account;
3635
import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
3736
import org.apache.cloudstack.quota.activationrule.presetvariables.Configuration;
3837
import org.apache.cloudstack.quota.activationrule.presetvariables.GenericPresetVariable;
@@ -63,6 +62,7 @@
6362

6463
import com.cloud.usage.UsageVO;
6564
import com.cloud.usage.dao.UsageDao;
65+
import com.cloud.user.Account;
6666
import com.cloud.user.AccountVO;
6767
import com.cloud.user.dao.AccountDao;
6868
import com.cloud.utils.DateUtil;
@@ -468,12 +468,7 @@ protected void injectPresetVariablesIntoJsInterpreter(JsInterpreter jsInterprete
468468

469469
}
470470

471-
Configuration configuration = presetVariables.getConfiguration();
472-
if (configuration != null) {
473-
jsInterpreter.injectVariable("configuration", configuration.toString());
474-
}
475-
476-
jsInterpreter.injectStringVariable("resourceType", presetVariables.getResourceType());
471+
jsInterpreter.injectVariable("resourceType", presetVariables.getResourceType());
477472
jsInterpreter.injectVariable("value", presetVariables.getValue().toString());
478473
jsInterpreter.injectVariable("zone", presetVariables.getZone().toString());
479474
}

framework/quota/src/test/java/org/apache/cloudstack/quota/QuotaManagerImplTest.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -270,8 +270,7 @@ public void injectPresetVariablesIntoJsInterpreterTestProjectIsNullDoNotInjectPr
270270
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("account"), Mockito.anyString());
271271
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("domain"), Mockito.anyString());
272272
Mockito.verify(jsInterpreterMock, Mockito.never()).injectVariable(Mockito.eq("project"), Mockito.anyString());
273-
Mockito.verify(jsInterpreterMock, Mockito.never()).injectVariable(Mockito.eq("configuration"), Mockito.anyString());
274-
Mockito.verify(jsInterpreterMock).injectStringVariable(Mockito.eq("resourceType"), Mockito.anyString());
273+
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("resourceType"), Mockito.anyString());
275274
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("value"), Mockito.anyString());
276275
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("zone"), Mockito.anyString());
277276
}
@@ -292,7 +291,7 @@ public void injectPresetVariablesIntoJsInterpreterTestProjectIsNotNullInjectProj
292291
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("account"), Mockito.anyString());
293292
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("domain"), Mockito.anyString());
294293
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("project"), Mockito.anyString());
295-
Mockito.verify(jsInterpreterMock).injectStringVariable(Mockito.eq("resourceType"), Mockito.anyString());
294+
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("resourceType"), Mockito.anyString());
296295
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("value"), Mockito.anyString());
297296
Mockito.verify(jsInterpreterMock).injectVariable(Mockito.eq("zone"), Mockito.anyString());
298297
}

plugins/database/quota/src/main/java/org/apache/cloudstack/api/response/QuotaResponseBuilderImpl.java

Lines changed: 17 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@
4242

4343
import javax.inject.Inject;
4444

45-
import com.cloud.utils.DateUtil;
4645
import com.cloud.utils.exception.CloudRuntimeException;
4746
import org.apache.cloudstack.api.ApiErrorCode;
4847
import org.apache.cloudstack.api.ServerApiException;
@@ -76,8 +75,8 @@
7675
import org.apache.cloudstack.quota.dao.QuotaEmailConfigurationDao;
7776
import org.apache.cloudstack.quota.dao.QuotaEmailTemplatesDao;
7877
import org.apache.cloudstack.quota.dao.QuotaTariffDao;
79-
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
8078
import org.apache.cloudstack.quota.dao.QuotaUsageDao;
79+
import org.apache.cloudstack.quota.vo.QuotaAccountVO;
8180
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
8281
import org.apache.cloudstack.quota.vo.QuotaCreditsVO;
8382
import org.apache.cloudstack.quota.vo.QuotaEmailConfigurationVO;
@@ -86,26 +85,28 @@
8685
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
8786
import org.apache.cloudstack.utils.jsinterpreter.JsInterpreter;
8887
import org.apache.cloudstack.utils.reflectiontostringbuilderutils.ReflectionToStringBuilderUtils;
88+
import org.apache.commons.lang3.ObjectUtils;
8989
import org.apache.commons.lang3.StringUtils;
9090
import org.apache.commons.lang3.reflect.FieldUtils;
91-
import org.apache.commons.lang3.ObjectUtils;
92-
import org.apache.logging.log4j.Logger;
9391
import org.apache.logging.log4j.LogManager;
92+
import org.apache.logging.log4j.Logger;
9493
import org.springframework.stereotype.Component;
9594

9695
import com.cloud.domain.DomainVO;
9796
import com.cloud.domain.dao.DomainDao;
97+
import com.cloud.event.ActionEvent;
98+
import com.cloud.event.EventTypes;
9899
import com.cloud.exception.InvalidParameterValueException;
100+
import com.cloud.exception.PermissionDeniedException;
99101
import com.cloud.user.Account;
100102
import com.cloud.user.AccountManager;
101103
import com.cloud.user.AccountVO;
102104
import com.cloud.user.User;
103105
import com.cloud.user.dao.AccountDao;
104106
import com.cloud.user.dao.UserDao;
107+
import com.cloud.utils.DateUtil;
105108
import com.cloud.utils.Pair;
106109
import com.cloud.utils.db.Filter;
107-
import com.cloud.event.ActionEvent;
108-
import com.cloud.event.EventTypes;
109110

110111
@Component
111112
public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
@@ -148,6 +149,12 @@ public class QuotaResponseBuilderImpl implements QuotaResponseBuilder {
148149
private final Class<?>[] assignableClasses = {GenericPresetVariable.class, ComputingResources.class};
149150

150151

152+
protected void checkActivationRulesAllowed(String activationRule) {
153+
if (!_quotaService.isJsInterpretationEnabled() && StringUtils.isNotEmpty(activationRule)) {
154+
throw new PermissionDeniedException("Quota Tariff Activation Rule cannot be set, as Javascript interpretation is disabled in the configuration.");
155+
}
156+
}
157+
151158
@Override
152159
public QuotaTariffResponse createQuotaTariffResponse(QuotaTariffVO tariff, boolean returnActivationRule) {
153160
final QuotaTariffResponse response = new QuotaTariffResponse();
@@ -449,6 +456,8 @@ public QuotaTariffVO updateQuotaTariffPlan(QuotaTariffUpdateCmd cmd) {
449456
throw new InvalidParameterValueException(String.format("There is no quota tariffs with name [%s].", name));
450457
}
451458

459+
checkActivationRulesAllowed(activationRule);
460+
452461
Date currentQuotaTariffStartDate = currentQuotaTariff.getEffectiveOn();
453462

454463
currentQuotaTariff.setRemoved(now);
@@ -705,6 +714,8 @@ public QuotaTariffVO createQuotaTariff(QuotaTariffCreateCmd cmd) {
705714
throw new InvalidParameterValueException(String.format("A quota tariff with name [%s] already exist.", name));
706715
}
707716

717+
checkActivationRulesAllowed(activationRule);
718+
708719
if (startDate.compareTo(now) < 0) {
709720
throw new InvalidParameterValueException(String.format("The value passed as Quota tariff's start date is in the past: [%s]. " +
710721
"Please, inform a date in the future or do not pass the parameter to use the current date and time.", startDate));

plugins/database/quota/src/main/java/org/apache/cloudstack/quota/QuotaService.java

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -16,15 +16,15 @@
1616
//under the License.
1717
package org.apache.cloudstack.quota;
1818

19-
import com.cloud.user.AccountVO;
20-
import com.cloud.utils.component.PluggableService;
19+
import java.math.BigDecimal;
20+
import java.util.Date;
21+
import java.util.List;
2122

2223
import org.apache.cloudstack.quota.vo.QuotaBalanceVO;
2324
import org.apache.cloudstack.quota.vo.QuotaUsageVO;
2425

25-
import java.math.BigDecimal;
26-
import java.util.Date;
27-
import java.util.List;
26+
import com.cloud.user.AccountVO;
27+
import com.cloud.utils.component.PluggableService;
2828

2929
public interface QuotaService extends PluggableService {
3030

@@ -40,4 +40,6 @@ public interface QuotaService extends PluggableService {
4040

4141
boolean saveQuotaAccount(AccountVO account, BigDecimal aggrUsage, Date endDate);
4242

43+
boolean isJsInterpretationEnabled();
44+
4345
}

plugins/database/quota/src/main/java/org/apache/cloudstack/quota/QuotaServiceImpl.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,7 @@
6161
import com.cloud.domain.dao.DomainDao;
6262
import com.cloud.exception.InvalidParameterValueException;
6363
import com.cloud.exception.PermissionDeniedException;
64+
import com.cloud.server.ManagementService;
6465
import com.cloud.user.Account;
6566
import com.cloud.user.AccountVO;
6667
import com.cloud.user.dao.AccountDao;
@@ -87,6 +88,8 @@ public class QuotaServiceImpl extends ManagerBase implements QuotaService, Confi
8788

8889
private TimeZone _usageTimezone;
8990

91+
private boolean jsInterpretationEnabled = false;
92+
9093
public QuotaServiceImpl() {
9194
super();
9295
}
@@ -98,6 +101,8 @@ public boolean configure(String name, Map<String, Object> params) throws Configu
98101
String timeZoneStr = ObjectUtils.defaultIfNull(_configDao.getValue(Config.UsageAggregationTimezone.toString()), "GMT");
99102
_usageTimezone = TimeZone.getTimeZone(timeZoneStr);
100103

104+
jsInterpretationEnabled = ManagementService.JsInterpretationEnabled.value();
105+
101106
return true;
102107
}
103108

@@ -286,4 +291,8 @@ public void setMinBalance(Long accountId, Double balance) {
286291
}
287292
}
288293

294+
@Override
295+
public boolean isJsInterpretationEnabled() {
296+
return jsInterpretationEnabled;
297+
}
289298
}

server/src/main/java/com/cloud/resource/ResourceManagerImpl.java

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,7 @@
178178
import com.cloud.org.Grouping;
179179
import com.cloud.org.Managed;
180180
import com.cloud.serializer.GsonHelper;
181+
import com.cloud.server.ManagementService;
181182
import com.cloud.service.ServiceOfferingVO;
182183
import com.cloud.service.dao.ServiceOfferingDao;
183184
import com.cloud.service.dao.ServiceOfferingDetailsDao;
@@ -308,6 +309,8 @@ public class ResourceManagerImpl extends ManagerBase implements ResourceManager,
308309
private UserVmManager userVmManager;
309310
@Inject
310311
private GpuService gpuService;
312+
@Inject
313+
ManagementService managementService;
311314

312315
private List<? extends Discoverer> _discoverers;
313316

@@ -2837,6 +2840,9 @@ private void updateHostTags(HostVO host, Long hostId, List<String> hostTags, Boo
28372840

28382841
@Override
28392842
public Host updateHost(final UpdateHostCmd cmd) throws NoTransitionException {
2843+
managementService.checkJsInterpretationAllowedIfNeededForParameterValue(ApiConstants.IS_TAG_A_RULE,
2844+
Boolean.TRUE.equals(cmd.getIsTagARule()));
2845+
28402846
return updateHost(cmd.getId(), cmd.getName(), cmd.getOsCategoryId(),
28412847
cmd.getAllocationState(), cmd.getUrl(), cmd.getHostTags(), cmd.getIsTagARule(), cmd.getAnnotation(), false,
28422848
cmd.getExternalDetails(), cmd.isCleanupExternalDetails(), cmd.getMigrationIp());

server/src/main/java/com/cloud/server/ManagementServerImpl.java

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1141,6 +1141,8 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
11411141

11421142
protected List<DeploymentPlanner> _planners;
11431143

1144+
private boolean jsInterpretationEnabled = false;
1145+
11441146
private final List<HypervisorType> supportedHypervisors = new ArrayList<>();
11451147

11461148
public List<DeploymentPlanner> getPlanners() {
@@ -1231,6 +1233,8 @@ public boolean configure(final String name, final Map<String, Object> params) th
12311233
supportedHypervisors.add(HypervisorType.KVM);
12321234
supportedHypervisors.add(HypervisorType.XenServer);
12331235

1236+
jsInterpretationEnabled = JsInterpretationEnabled.value();
1237+
12341238
return true;
12351239
}
12361240

@@ -4605,8 +4609,10 @@ public List<Class<?>> getCommands() {
46054609
cmdList.add(ListGuestVlansCmd.class);
46064610
cmdList.add(AssignVolumeCmd.class);
46074611
cmdList.add(ListSecondaryStorageSelectorsCmd.class);
4608-
cmdList.add(CreateSecondaryStorageSelectorCmd.class);
4609-
cmdList.add(UpdateSecondaryStorageSelectorCmd.class);
4612+
if (jsInterpretationEnabled) {
4613+
cmdList.add(CreateSecondaryStorageSelectorCmd.class);
4614+
cmdList.add(UpdateSecondaryStorageSelectorCmd.class);
4615+
}
46104616
cmdList.add(RemoveSecondaryStorageSelectorCmd.class);
46114617
cmdList.add(ListAffectedVmsForStorageScopeChangeCmd.class);
46124618
cmdList.add(ListGuiThemesCmd.class);
@@ -4671,7 +4677,8 @@ public String getConfigComponentName() {
46714677

46724678
@Override
46734679
public ConfigKey<?>[] getConfigKeys() {
4674-
return new ConfigKey<?>[] {exposeCloudStackVersionInApiXmlResponse, exposeCloudStackVersionInApiListCapabilities, vmPasswordLength, sshKeyLength, humanReadableSizes, customCsIdentifier};
4680+
return new ConfigKey<?>[] {vmPasswordLength, sshKeyLength, humanReadableSizes, customCsIdentifier,
4681+
JsInterpretationEnabled};
46754682
}
46764683

46774684
protected class EventPurgeTask extends ManagedContextRunnable {
@@ -6415,4 +6422,14 @@ public boolean removeManagementServer(RemoveManagementServerCmd cmd) {
64156422
public Answer getExternalVmConsole(VirtualMachine vm, Host host) {
64166423
return extensionsManager.getInstanceConsole(vm, host);
64176424
}
6425+
6426+
@Override
6427+
public void checkJsInterpretationAllowedIfNeededForParameterValue(String paramName, boolean paramValue) {
6428+
if (!paramValue || jsInterpretationEnabled) {
6429+
return;
6430+
}
6431+
throw new InvalidParameterValueException(String.format(
6432+
"The parameter %s cannot be set to true as JS interpretation is disabled",
6433+
paramName));
6434+
}
64186435
}

server/src/main/java/com/cloud/storage/StorageManagerImpl.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,7 @@
221221
import com.cloud.resource.ResourceState;
222222
import com.cloud.server.ConfigurationServer;
223223
import com.cloud.server.ManagementServer;
224+
import com.cloud.server.ManagementService;
224225
import com.cloud.server.StatsCollector;
225226
import com.cloud.service.dao.ServiceOfferingDetailsDao;
226227
import com.cloud.storage.Storage.ImageFormat;
@@ -414,6 +415,8 @@ public class StorageManagerImpl extends ManagerBase implements StorageManager, C
414415
ResourceManager _resourceMgr;
415416
@Inject
416417
StorageManager storageManager;
418+
@Inject
419+
ManagementService managementService;
417420

418421
protected List<StoragePoolDiscoverer> _discoverers;
419422

@@ -1031,6 +1034,9 @@ public PrimaryDataStoreInfo createPool(CreateStoragePoolCmd cmd) throws Resource
10311034
throw new PermissionDeniedException(String.format("Cannot perform this operation, Zone is currently disabled: %s", zone));
10321035
}
10331036

1037+
managementService.checkJsInterpretationAllowedIfNeededForParameterValue(ApiConstants.IS_TAG_A_RULE,
1038+
Boolean.TRUE.equals(cmd.isTagARule()));
1039+
10341040
Map<String, Object> params = new HashMap<>();
10351041
params.put("zoneId", zone.getId());
10361042
params.put("clusterId", clusterId);
@@ -1215,6 +1221,9 @@ public PrimaryDataStoreInfo updateStoragePool(UpdateStoragePoolCmd cmd) throws I
12151221
// Input validation
12161222
Long id = cmd.getId();
12171223

1224+
managementService.checkJsInterpretationAllowedIfNeededForParameterValue(ApiConstants.IS_TAG_A_RULE,
1225+
Boolean.TRUE.equals(cmd.isTagARule()));
1226+
12181227
StoragePoolVO pool = _storagePoolDao.findById(id);
12191228
if (pool == null) {
12201229
throw new IllegalArgumentException("Unable to find storage pool with ID: " + id);

0 commit comments

Comments
 (0)