pulled from master

This commit is contained in:
Alex Huang 2013-01-10 16:01:01 -08:00
commit 1294cdc701
21 changed files with 690 additions and 634 deletions

View File

@ -20,6 +20,7 @@ import java.util.List;
import java.util.Map;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.command.admin.user.DeleteUserCmd;
@ -193,6 +194,8 @@ public interface AccountService {
UserAccount getUserByApiKey(String apiKey);
RoleType getRoleType(Account account);
void checkAccess(Account account, Domain domain) throws PermissionDeniedException;
void checkAccess(Account account, AccessType accessType, boolean sameOwner, ControlledEntity... entities) throws PermissionDeniedException;

View File

@ -0,0 +1,37 @@
// 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.cloudstack.acl;
// Enum for default roles in CloudStack
public enum RoleType {
Admin(1),
ResourceAdmin(2),
DomainAdmin(4),
User(8),
Unknown(0);
private int mask;
private RoleType(int mask) {
this.mask = mask;
}
public int getValue() {
return mask;
}
}

View File

@ -1,23 +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.
# bitmap of permissions at the end of each classname, 1 = ADMIN, 2 =
# RESOURCE_DOMAIN_ADMIN, 4 = DOMAIN_ADMIN, 8 = USER
# Please standardize naming conventions to camel-case (even for acronyms).
# CloudStack API Discovery service command
listApis=15

View File

@ -16,17 +16,15 @@
// under the License.
package org.apache.cloudstack.acl;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import static org.apache.cloudstack.acl.RoleType.Admin;
import static org.apache.cloudstack.acl.RoleType.DomainAdmin;
import static org.apache.cloudstack.acl.RoleType.ResourceAdmin;
import static org.apache.cloudstack.acl.RoleType.User;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import javax.ejb.Local;
@ -37,7 +35,6 @@ import org.apache.log4j.Logger;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.user.AccountManager;
import com.cloud.utils.PropertiesUtil;
import com.cloud.utils.component.AdapterBase;
import com.cloud.utils.component.PluggableService;
@ -70,104 +67,70 @@ public class StaticRoleBasedAPIAccessChecker extends AdapterBase implements APIA
}
@Override
public boolean canAccessAPI(RoleType roleType, String apiCommandName)
throws PermissionDeniedException{
public boolean canAccessAPI(RoleType roleType, String commandName)
throws PermissionDeniedException {
boolean commandExists = s_allCommands.contains(apiCommandName);
boolean commandExists = s_allCommands.contains(commandName);
boolean commandAccessible = false;
if(commandExists) {
return isCommandAvailableForAccount(roleType, apiCommandName);
if (commandExists) {
switch (roleType) {
case Admin:
commandAccessible = s_adminCommands.contains(commandName);
break;
case DomainAdmin:
commandAccessible = s_resellerCommands.contains(commandName);
break;
case ResourceAdmin:
commandAccessible = s_resourceDomainAdminCommands.contains(commandName);
break;
case User:
commandAccessible = s_userCommands.contains(commandName);
break;
}
}
return commandExists;
}
private static boolean isCommandAvailableForAccount(RoleType roleType, String commandName) {
boolean isCommandAvailable = false;
switch (roleType) {
case Admin:
isCommandAvailable = s_adminCommands.contains(commandName);
break;
case DomainAdmin:
isCommandAvailable = s_resellerCommands.contains(commandName);
break;
case ResourceAdmin:
isCommandAvailable = s_resourceDomainAdminCommands.contains(commandName);
break;
case User:
isCommandAvailable = s_userCommands.contains(commandName);
break;
}
return isCommandAvailable;
return commandExists && commandAccessible;
}
@Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {
super.configure(name, params);
List<String> configFiles = new ArrayList<String>();
// Read command properties files to build the static map per role.
Map<String, String> configPropertiesMap = new HashMap<String, String>();
for (PluggableService service : _services) {
configFiles.addAll(Arrays.asList(service.getPropertiesFiles()));
configPropertiesMap.putAll(service.getProperties());
}
processConfigFiles(configFiles);
processConfigFiles(configPropertiesMap);
return true;
}
private void processConfigFiles(List<String> configFiles) {
Properties preProcessedCommands = new Properties();
for (String configFile : configFiles) {
File commandsFile = PropertiesUtil.findConfigFile(configFile);
if (commandsFile != null) {
try {
preProcessedCommands.load(new FileInputStream(commandsFile));
} catch (FileNotFoundException fnfex) {
// in case of a file within a jar in classpath, try to open stream using url
InputStream stream = PropertiesUtil.openStreamFromURL(configFile);
if (stream != null) {
try {
preProcessedCommands.load(stream);
} catch (IOException e) {
s_logger.error("IO Exception, unable to find properties file:", fnfex);
}
} else {
s_logger.error("Unable to find properites file", fnfex);
}
} catch (IOException ioe) {
s_logger.error("IO Exception loading properties file", ioe);
}
}
}
for (Object key : preProcessedCommands.keySet()) {
String preProcessedCommand = preProcessedCommands.getProperty((String) key);
int splitIndex = preProcessedCommand.lastIndexOf(";");
// Backward compatible to old style, apiname=pkg;mask
String mask = preProcessedCommand.substring(splitIndex+1);
private void processConfigFiles(Map<String, String> config) {
for (Map.Entry<String, String> entry: config.entrySet()) {
String apiName = entry.getKey();
String roleMask = entry.getValue();
try {
short cmdPermissions = Short.parseShort(mask);
short cmdPermissions = Short.parseShort(roleMask);
if ((cmdPermissions & Admin.getValue()) != 0) {
s_adminCommands.add((String) key);
s_adminCommands.add(apiName);
}
if ((cmdPermissions & ResourceAdmin.getValue()) != 0) {
s_resourceDomainAdminCommands.add((String) key);
s_resourceDomainAdminCommands.add(apiName);
}
if ((cmdPermissions & DomainAdmin.getValue()) != 0) {
s_resellerCommands.add((String) key);
s_resellerCommands.add(apiName);
}
if ((cmdPermissions & User.getValue()) != 0) {
s_userCommands.add((String) key);
s_userCommands.add(apiName);
}
s_allCommands.addAll(s_adminCommands);
s_allCommands.addAll(s_resourceDomainAdminCommands);
s_allCommands.addAll(s_userCommands);
s_allCommands.addAll(s_resellerCommands);
} catch (NumberFormatException nfe) {
s_logger.info("Malformed command.properties permissions value, key = " + key + ", value = " + preProcessedCommand);
s_logger.info("Malformed commands.properties permissions value, for entry: " + entry.toString());
}
}
s_allCommands.addAll(s_adminCommands);
s_allCommands.addAll(s_resourceDomainAdminCommands);
s_allCommands.addAll(s_userCommands);
s_allCommands.addAll(s_resellerCommands);
}
}

View File

@ -16,6 +16,9 @@
// under the License.
package org.apache.cloudstack.api.command.user.discovery;
import com.cloud.user.Account;
import com.cloud.user.UserContext;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.BaseListCmd;
@ -39,7 +42,9 @@ public class ListApisCmd extends BaseListCmd {
@Override
public void execute() throws ServerApiException {
if (_apiDiscoveryService != null) {
ListResponse<ApiDiscoveryResponse> response = (ListResponse<ApiDiscoveryResponse>) _apiDiscoveryService.listApis();
Account caller = UserContext.current().getCaller();
RoleType roleType = _accountService.getRoleType(UserContext.current().getCaller());
ListResponse<ApiDiscoveryResponse> response = (ListResponse<ApiDiscoveryResponse>) _apiDiscoveryService.listApis(roleType);
if (response == null) {
throw new ServerApiException(BaseCmd.INTERNAL_ERROR, "Api Discovery plugin was unable to find and process any apis");
}

View File

@ -17,9 +17,10 @@
package org.apache.cloudstack.discovery;
import com.cloud.utils.component.PluggableService;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.response.ListResponse;
public interface ApiDiscoveryService extends PluggableService {
ListResponse<? extends BaseResponse> listApis();
ListResponse<? extends BaseResponse> listApis(RoleType roleType);
}

View File

@ -16,7 +16,9 @@
// under the License.
package org.apache.cloudstack.discovery;
import com.cloud.utils.PropertiesUtil;
import com.cloud.utils.ReflectUtil;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.BaseAsyncCmd;
@ -108,12 +110,14 @@ public class ApiDiscoveryServiceImpl implements ApiDiscoveryService {
}
@Override
public ListResponse<? extends BaseResponse> listApis() {
public ListResponse<? extends BaseResponse> listApis(RoleType roleType) {
return _discoveryResponse;
}
@Override
public String[] getPropertiesFiles() {
return new String[] { "api-discovery_commands.properties" };
public Map<String, String> getProperties() {
Map<String, String> apiDiscoveryPropertyMap = new HashMap<String, String>();
apiDiscoveryPropertyMap.put("listApis", "15");
return apiDiscoveryPropertyMap;
}
}

View File

@ -17,16 +17,16 @@
package com.cloud.server;
import com.cloud.utils.PropertiesUtil;
import java.util.Map;
public class ManagementServerSimulatorImpl extends ManagementServerExtImpl {
@Override
public String[] getPropertiesFiles() {
String[] apis = super.getPropertiesFiles();
String[] newapis = new String[apis.length + 1];
for (int i = 0; i < apis.length; i++) {
newapis[i] = apis[i];
}
newapis[apis.length] = "commands-simulator.properties";
return newapis;
public Map<String, String> getProperties() {
Map<String, String> apiNameRoleMaskMapping = super.getProperties();
apiNameRoleMaskMapping.putAll(PropertiesUtil.processConfigFile(new String[]
{"commands-simulator.properties"}));
return apiNameRoleMaskMapping;
}
}

View File

@ -17,6 +17,7 @@
package com.cloud.network.element;
import java.lang.String;
import java.util.List;
import java.util.Map;
import java.util.ArrayList;
@ -25,6 +26,7 @@ import java.util.Set;
import javax.ejb.Local;
import javax.inject.Inject;
import com.cloud.utils.PropertiesUtil;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@ -239,7 +241,8 @@ public class CiscoNexusVSMElement extends CiscoNexusVSMDeviceManagerImpl impleme
}
@Override
public String[] getPropertiesFiles() {
return new String[] { "cisconexusvsm_commands.properties" };
public Map<String, String> getProperties() {
return PropertiesUtil.processConfigFile(new String[]
{ "cisconexusvsm_commands.properties" });
}
}

View File

@ -16,6 +16,7 @@
// under the License.
package com.cloud.network.element;
import java.lang.String;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -25,6 +26,7 @@ import java.util.Set;
import javax.ejb.Local;
import javax.inject.Inject;
import com.cloud.utils.PropertiesUtil;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@ -262,8 +264,9 @@ public class F5ExternalLoadBalancerElement extends ExternalLoadBalancerDeviceMan
}
@Override
public String[] getPropertiesFiles() {
return new String[] { "f5bigip_commands.properties" };
public Map<String, String> getProperties() {
return PropertiesUtil.processConfigFile(new String[]
{ "f5bigip_commands.properties" });
}
@Override

View File

@ -16,6 +16,7 @@
// under the License.
package com.cloud.network.element;
import java.lang.String;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
@ -25,6 +26,7 @@ import java.util.Set;
import javax.ejb.Local;
import javax.inject.Inject;
import com.cloud.utils.PropertiesUtil;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@ -404,8 +406,9 @@ public class JuniperSRXExternalFirewallElement extends ExternalFirewallDeviceMan
}
@Override
public String[] getPropertiesFiles() {
return new String[] { "junipersrx_commands.properties"};
public Map<String, String> getProperties() {
return PropertiesUtil.processConfigFile(new String[]
{ "junipersrx_commands.properties"});
}
@Override

View File

@ -27,6 +27,7 @@ import java.util.Set;
import javax.ejb.Local;
import javax.inject.Inject;
import com.cloud.utils.PropertiesUtil;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;
@ -466,8 +467,9 @@ StaticNatServiceProvider {
}
@Override
public String[] getPropertiesFiles() {
return new String[] { "netscalerloadbalancer_commands.properties" };
public Map<String, String> getProperties() {
return PropertiesUtil.processConfigFile(new String[]
{ "netscalerloadbalancer_commands.properties" });
}
@Override

View File

@ -52,6 +52,8 @@ import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.apache.cloudstack.acl.APIAccessChecker;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.BaseAsyncCreateCmd;
import org.apache.cloudstack.api.BaseCmd;
@ -62,9 +64,6 @@ import org.apache.cloudstack.api.command.admin.host.ListHostsCmd;
import org.apache.cloudstack.api.command.admin.router.ListRoutersCmd;
import org.apache.cloudstack.api.command.admin.storage.ListStoragePoolsCmd;
import org.apache.cloudstack.api.command.admin.user.ListUsersCmd;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.*;
import org.apache.cloudstack.api.command.user.account.ListAccountsCmd;
import org.apache.cloudstack.api.command.user.account.ListProjectAccountsCmd;
import org.apache.cloudstack.api.command.user.event.ListEventsCmd;
@ -75,12 +74,8 @@ import org.apache.cloudstack.api.command.user.tag.ListTagsCmd;
import org.apache.cloudstack.api.command.user.vm.ListVMsCmd;
import org.apache.cloudstack.api.command.user.vmgroup.ListVMGroupsCmd;
import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd;
<<<<<<< HEAD
import org.apache.cloudstack.api.response.ExceptionResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.discovery.ApiDiscoveryService;
=======
>>>>>>> master
import org.apache.commons.codec.binary.Base64;
import org.apache.http.ConnectionClosedException;
import org.apache.http.HttpException;
@ -133,6 +128,7 @@ import com.cloud.user.UserAccount;
import com.cloud.user.UserContext;
import com.cloud.user.UserVO;
import com.cloud.utils.Pair;
import com.cloud.utils.ReflectUtil;
import com.cloud.utils.StringUtils;
import com.cloud.utils.component.ComponentContext;
import com.cloud.utils.component.PluggableService;
@ -179,7 +175,7 @@ public class ApiServer implements HttpRequestHandler {
if (s_instance == null) {
s_instance = new ApiServer();
s_instance = ComponentContext.inject(s_instance);
s_instance.init(apiConfig);
s_instance.init();
}
}
@ -798,37 +794,14 @@ public class ApiServer implements HttpRequestHandler {
return true;
}
private boolean isCommandAvailable(User user, String commandName) {
private boolean isCommandAvailable(User user, String commandName)
throws PermissionDeniedException {
if (user == null) {
return false;
}
Account account = _accountMgr.getAccount(user.getAccountId());
if (account == null) {
return false;
}
RoleType roleType = RoleType.Unknown;
short accountType = account.getType();
// Account type to role type translation
switch (accountType) {
case Account.ACCOUNT_TYPE_ADMIN:
roleType = RoleType.Admin;
break;
case Account.ACCOUNT_TYPE_DOMAIN_ADMIN:
roleType = RoleType.DomainAdmin;
break;
case Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN:
roleType = RoleType.ResourceAdmin;
break;
case Account.ACCOUNT_TYPE_NORMAL:
roleType = RoleType.User;
break;
default:
return false;
}
RoleType roleType = _accountMgr.getRoleType(account);
for (APIAccessChecker apiChecker : _apiAccessCheckers) {
// Fail the checking if any checker fails to verify
if (!apiChecker.canAccessAPI(roleType, commandName))

View File

@ -25,6 +25,7 @@ import java.util.Set;
import javax.ejb.Local;
import javax.inject.Inject;
import com.cloud.utils.PropertiesUtil;
import org.apache.cloudstack.api.command.admin.router.ConfigureVirtualRouterElementCmd;
import org.apache.cloudstack.api.command.admin.router.ListVirtualRouterElementsCmd;
import org.apache.log4j.Logger;
@ -682,8 +683,9 @@ public class VirtualRouterElement extends AdapterBase implements VirtualRouterEl
}
@Override
public String[] getPropertiesFiles() {
return new String[] { "virtualrouter_commands.properties" };
public Map<String, String> getProperties() {
return PropertiesUtil.processConfigFile(new String[]
{ "virtualrouter_commands.properties" });
}
@Override

View File

@ -32,6 +32,7 @@ import com.cloud.domain.dao.DomainDao;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.projects.Project;
import com.cloud.utils.PropertiesUtil;
import org.apache.cloudstack.api.response.UsageTypeResponse;
import org.springframework.stereotype.Component;
@ -209,8 +210,9 @@ public class ManagementServerExtImpl extends ManagementServerImpl implements Man
}
@Override
public String[] getPropertiesFiles() {
return new String[] { "commands.properties", "commands-ext.properties" };
public Map<String, String> getProperties() {
return PropertiesUtil.processConfigFile(new String[]
{ "commands.properties", "commands-ext.properties" });
}
private Date computeAdjustedTime(Date initialDate, TimeZone targetTZ, boolean adjustToDayStart) {

View File

@ -223,6 +223,7 @@ import com.cloud.utils.EnumUtils;
import com.cloud.utils.NumbersUtil;
import com.cloud.utils.Pair;
import com.cloud.utils.PasswordGenerator;
import com.cloud.utils.PropertiesUtil;
import com.cloud.utils.Ternary;
import com.cloud.utils.component.Adapter;
import com.cloud.utils.component.ComponentContext;
@ -2392,8 +2393,9 @@ public class ManagementServerImpl implements ManagementServer {
}
@Override
public String[] getPropertiesFiles() {
return new String[] { "commands.properties" };
public Map<String, String> getProperties() {
return PropertiesUtil.processConfigFile(new String[]
{ "commands.properties" });
}
protected class EventPurgeTask implements Runnable {

View File

@ -38,6 +38,7 @@ import javax.inject.Inject;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.command.admin.account.UpdateAccountCmd;
@ -1537,6 +1538,31 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag
}
}
@Override
public RoleType getRoleType(Account account) {
RoleType roleType = RoleType.Unknown;
if (account == null)
return roleType;
short accountType = account.getType();
// Account type to role type translation
switch (accountType) {
case Account.ACCOUNT_TYPE_ADMIN:
roleType = RoleType.Admin;
break;
case Account.ACCOUNT_TYPE_DOMAIN_ADMIN:
roleType = RoleType.DomainAdmin;
break;
case Account.ACCOUNT_TYPE_RESOURCE_DOMAIN_ADMIN:
roleType = RoleType.ResourceAdmin;
break;
case Account.ACCOUNT_TYPE_NORMAL:
roleType = RoleType.User;
break;
}
return roleType;
}
@Override
public User getActiveUser(long userId) {
return _userDao.findById(userId);

View File

@ -23,6 +23,7 @@ import javax.ejb.Local;
import javax.naming.ConfigurationException;
import org.apache.cloudstack.acl.ControlledEntity;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import com.cloud.api.query.vo.ControlledViewEntity;
@ -344,4 +345,9 @@ public class MockAccountManagerImpl implements Manager, AccountManager, AccountS
return null;
}
@Override
public RoleType getRoleType(Account account) {
return null;
}
}

View File

@ -17,6 +17,8 @@
package com.cloud.utils;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
@ -28,6 +30,7 @@ import java.util.Set;
import org.apache.log4j.Logger;
public class PropertiesUtil {
private static final Logger s_logger = Logger.getLogger(PropertiesUtil.class);
/**
* Searches the class path and local paths to find the config file.
* @param path path to find. if it starts with / then it's absolute path.
@ -116,4 +119,41 @@ public class PropertiesUtil {
}
return null;
}
// Returns key=value pairs by parsing a commands.properties/config file
// with syntax; key=cmd;value (with this syntax cmd is stripped) and key=value
public static Map<String, String> processConfigFile(String[] configFiles) {
Map<String, String> configMap = new HashMap<String, String>();
Properties preProcessedCommands = new Properties();
for (String configFile : configFiles) {
File commandsFile = findConfigFile(configFile);
if (commandsFile != null) {
try {
preProcessedCommands.load(new FileInputStream(commandsFile));
} catch (FileNotFoundException fnfex) {
// in case of a file within a jar in classpath, try to open stream using url
InputStream stream = PropertiesUtil.openStreamFromURL(configFile);
if (stream != null) {
try {
preProcessedCommands.load(stream);
} catch (IOException e) {
s_logger.error("IO Exception, unable to find properties file:", fnfex);
}
} else {
s_logger.error("Unable to find properites file", fnfex);
}
} catch (IOException ioe) {
s_logger.error("IO Exception loading properties file", ioe);
}
}
}
for (Object key : preProcessedCommands.keySet()) {
String preProcessedCommand = preProcessedCommands.getProperty((String) key);
int splitIndex = preProcessedCommand.lastIndexOf(";");
String value = preProcessedCommand.substring(splitIndex+1);
configMap.put((String)key, value);
}
return configMap;
}
}

View File

@ -16,9 +16,11 @@
// under the License.
package com.cloud.utils.component;
import java.util.Map;
// This interface defines methods for pluggable code within the Cloud Stack.
public interface PluggableService {
// The config command properties filenames that lists allowed API commands
// and role masks supported by this pluggable service
String[] getPropertiesFiles();
Map<String, String> getProperties();
}