Connected config gathering to CloudStack

This commit is contained in:
Alex Huang 2013-08-06 11:03:38 -07:00
parent 90cfca0501
commit 49cd4fa380
13 changed files with 166 additions and 31 deletions

View File

@ -16,18 +16,69 @@
// under the License. // under the License.
package org.apache.cloudstack.config; package org.apache.cloudstack.config;
import java.util.Date;
/**
* Configuration represents one global configuration parameter for CloudStack.
* Its scope should indicate whether this parameter can be set at different
* organization levels in CloudStack.
*
*/
public interface Configuration { public interface Configuration {
public String getCategory(); /**
* @return Category of the parameter.
*/
String getCategory();
public String getInstance(); /**
* @return Server instance that uses this parameter.
*/
String getInstance();
public String getComponent(); /**
* @return Component that introduced this parameter.
*/
String getComponent();
public String getName(); /**
* @return Name of the parameter.
*/
String getName();
public String getValue(); /**
* @return Value set by the administrator. Defaults to the defaultValue.
*/
String getValue();
public String getDescription(); /**
* @return Description of the value and the range of the value.
*/
String getDescription();
/**
* @return Default value for this parameter. Cannot be null.
*/
String getDefaultValue();
/**
* @return Scope for the parameter. Null indicates that this parameter is
* always global. A non-null value indicates that this parameter can be
* set at a certain organization level.
*/
String getScope();
/**
* @return can the configuration parameter be changed without restarting the server.
*/
boolean isDynamic();
/**
* @return The date this VO was updated by the components. Note that this is not
* a date for when an administrator updates the value. This is when the system
* updated this value. By searching on this field gives you all the config
* parameters that have changed in an upgrade. Null value indicates that this
* parameter is no longer used and can be deleted.
*/
Date getUpdated();
} }

View File

@ -1028,9 +1028,9 @@ public class ClusterManagerImpl extends ManagerBase implements ClusterManager {
} }
protected final ConfigKey<Integer> HeartBeatInterval = new ConfigKey<Integer>(Integer.class, "cluster.heartbeat.interval", "management-server", protected final ConfigKey<Integer> HeartBeatInterval = new ConfigKey<Integer>(Integer.class, "cluster.heartbeat.interval", "management-server",
"1500", "Interval to check for the heart beat between management server nodes", false, "Seconds"); "1500", "Interval to check for the heart beat between management server nodes", false);
protected final ConfigKey<Integer> HeartBeatThreshold = new ConfigKey<Integer>(Integer.class, "cluster.heartbeat.threshold", "management-server", protected final ConfigKey<Integer> HeartBeatThreshold = new ConfigKey<Integer>(Integer.class, "cluster.heartbeat.threshold", "management-server",
"150000", "Threshold before self-fence the management server", true, "Seconds"); "150000", "Threshold before self-fence the management server", true);
@Override @Override
public boolean configure(String name, Map<String, Object> params) throws ConfigurationException { public boolean configure(String name, Map<String, Object> params) throws ConfigurationException {

View File

@ -126,7 +126,7 @@ public class ClusterServiceServletAdapter extends AdapterBase implements Cluster
} }
private final ConfigKey<Integer> ClusterMessageTimeOut = new ConfigKey<Integer>(Integer.class, "cluster.message.timeout.seconds", "Advance", "300", private final ConfigKey<Integer> ClusterMessageTimeOut = new ConfigKey<Integer>(Integer.class, "cluster.message.timeout.seconds", "Advance", "300",
"Time (in seconds) to wait before a inter-management server message post times out.", true, "Seconds"); "Time (in seconds) to wait before a inter-management server message post times out.", true);
private void init() throws ConfigurationException { private void init() throws ConfigurationException {
if(_mshostDao != null) if(_mshostDao != null)

View File

@ -22,4 +22,6 @@ package org.apache.cloudstack.framework.config;
*/ */
public interface ConfigDepot { public interface ConfigDepot {
<T> ConfigValue<T> get(ConfigKey<T> key); <T> ConfigValue<T> get(ConfigKey<T> key);
<T> ScopedConfigValue<T> getScopedValue(ConfigKey<T> key);
} }

View File

@ -23,6 +23,13 @@ import java.util.List;
* *
*/ */
public interface ConfigDepotAdmin { public interface ConfigDepotAdmin {
/**
* Create configurations if there are new config parameters.
* Update configurations if the parameter settings have been changed.
* All configurations that have been updated/created will have the same timestamp in the updated field.
* All previous configurations that should be obsolete will have a null updated field.
* @see Configuration
*/
void populateConfigurations(); void populateConfigurations();
List<String> getComponentsInDepot(); List<String> getComponentsInDepot();

View File

@ -27,7 +27,25 @@ import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import com.cloud.utils.db.EntityManager; import com.cloud.utils.db.EntityManager;
/** /**
* DepotImpl implements the ConfigDepot interface * ConfigDepotImpl implements the ConfigDepot and ConfigDepotAdmin interface.
* Its functionalities include:
* - Control how dynamic config values are cached and refreshed.
* - Control how scoped config values are stored.
* - Gather all of the Configurable interfaces and insert their config
* variables into the config table.
* - Hide the data source where configs are stored and retrieved.
*
* When dealing with this class, we must be very careful on cluster situations.
*
* TODO:
* - Move the rest of the changes to the config table to here.
* - Implement ScopedConfigValue
* - Move the code to set scoped configuration values to here.
* - Add the code to mark the rows in configuration table without
* the corresponding keys to be null.
* - Move all of the configurations to using ConfigDepot
* - Completely eliminate Config.java
* - Figure out the correct categories.
* *
*/ */
class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin { class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin {
@ -48,6 +66,13 @@ class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin {
return new ConfigValue<T>(_entityMgr, config); return new ConfigValue<T>(_entityMgr, config);
} }
@Override
public <T> ScopedConfigValue<T> getScopedValue(ConfigKey<T> config) {
assert (config.scope() != null) : "Did you notice the configuration you're trying to retrieve is not scoped?";
return new ScopedConfigValue<T>(_entityMgr, config);
}
@Override @Override
public void populateConfigurations() { public void populateConfigurations() {
Date date = new Date(); Date date = new Date();
@ -70,8 +95,6 @@ class ConfigDepotImpl implements ConfigDepot, ConfigDepotAdmin {
} }
} }
} }
// TODO: Missing code to remove the updated field if the a configurationVO's name cannot be found any more.
} }
} }

View File

@ -16,14 +16,12 @@
// under the License. // under the License.
package org.apache.cloudstack.framework.config; package org.apache.cloudstack.framework.config;
import com.cloud.org.Grouping;
/** /**
* ConfigKey supplants the original Config.java. It is just a class * ConfigKey supplants the original Config.java. It is just a class
* declaration where others can declare their config variables. * declaration where others can declare their config variables.
* *
* TODO: This class should be moved to a framework project where the gathering
* of these configuration keys should be done by a config server. I
* don't have time yet to do this. Ask me about it if you want to work
* in this area. Right now, we'll just work with the actual names.
*/ */
public class ConfigKey<T> { public class ConfigKey<T> {
@ -49,7 +47,7 @@ public class ConfigKey<T> {
return _description; return _description;
} }
public String scope() { public Class<? extends Grouping> scope() {
return _scope; return _scope;
} }
@ -66,11 +64,11 @@ public class ConfigKey<T> {
private final String _name; private final String _name;
private final String _defaultValue; private final String _defaultValue;
private final String _description; private final String _description;
private final String _scope; // Parameter can be at different levels (Zone/cluster/pool/account), by default every parameter is at global private final Class<? extends Grouping> _scope; // Parameter can be at different levels (Zone/cluster/pool/account), by default every parameter is at global
private final boolean _isDynamic; private final boolean _isDynamic;
public ConfigKey(Class<T> type, String name, String category, String defaultValue, String description, boolean isDynamic, public ConfigKey(Class<T> type, String name, String category, String defaultValue, String description, boolean isDynamic,
String scope) { Class<? extends Grouping> scope) {
_category = category; _category = category;
_type = type; _type = type;
_name = name; _name = name;

View File

@ -16,6 +16,14 @@
// under the License. // under the License.
package org.apache.cloudstack.framework.config; package org.apache.cloudstack.framework.config;
/**
* Configurable can be implemented by components to insert their own
* configuration keys.
*
* CloudStack will gather all of these configurations at startup and insert
* them into the configuration table.
*
*/
public interface Configurable { public interface Configurable {
String getConfigComponentName(); String getConfigComponentName();

View File

@ -80,7 +80,7 @@ public class ConfigurationVO implements Configuration {
this(key.category(), "DEFAULT", component, key.key(), key.defaultValue(), key.description()); this(key.category(), "DEFAULT", component, key.key(), key.defaultValue(), key.description());
defaultValue = key.defaultValue(); defaultValue = key.defaultValue();
dynamic = key.isDynamic(); dynamic = key.isDynamic();
scope = key.scope(); scope = key.scope().getName();
} }
@Override @Override

View File

@ -0,0 +1,43 @@
// 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.framework.config;
import com.cloud.dc.DataCenter;
import com.cloud.dc.Pod;
import com.cloud.org.Cluster;
import com.cloud.org.Grouping;
import com.cloud.utils.db.EntityManager;
public class ScopedConfigValue<T> extends ConfigValue<T> {
public T getValueForScope(long scopeId) {
// TODO: In order to complete this the details for zone, pod, cluster
// needs to have interfaces. Then you can use the EntityManager to
// retrieve those information.
Class<? extends Grouping> scope = _config.scope();
if (scope == DataCenter.class) {
} else if (scope == Pod.class) {
} else if (scope == Cluster.class) {
}
return null;
}
protected ScopedConfigValue(EntityManager entityMgr, ConfigKey<T> key) {
super(entityMgr, key);
}
}

View File

@ -179,17 +179,16 @@ public class AgentManagerImpl extends ManagerBase implements AgentManager, Handl
protected ConfigDepot _configDepot; protected ConfigDepot _configDepot;
protected final ConfigKey<Integer> Workers = new ConfigKey<Integer>(Integer.class, "workers", "Advance", "5", protected final ConfigKey<Integer> Workers = new ConfigKey<Integer>(Integer.class, "workers", "Advance", "5",
"Number of worker threads handling remote agent connections.", false, "5-Max Thread Limit"); "Number of worker threads handling remote agent connections.", false);
protected final ConfigKey<Integer> Port = new ConfigKey<Integer>(Integer.class, "port", "Advance", "8250", "Port to listen on for remote agent connections.", false, protected final ConfigKey<Integer> Port = new ConfigKey<Integer>(Integer.class, "port", "Advance", "8250", "Port to listen on for remote agent connections.", false);
"Usable port range");
protected final ConfigKey<Integer> PingInterval = new ConfigKey<Integer>(Integer.class, "ping.interval", "Advance", "60", protected final ConfigKey<Integer> PingInterval = new ConfigKey<Integer>(Integer.class, "ping.interval", "Advance", "60",
"Interval to send application level pings to make sure the connection is still working", false, "Seconds"); "Interval to send application level pings to make sure the connection is still working", false);
protected final ConfigKey<Float> PingTimeout = new ConfigKey<Float>(Float.class, "ping.timeout", "Advance", "2.5", protected final ConfigKey<Float> PingTimeout = new ConfigKey<Float>(Float.class, "ping.timeout", "Advance", "2.5",
"Multiplier to ping.interval before announcing an agent has timed out", true, null); "Multiplier to ping.interval before announcing an agent has timed out", true);
protected final ConfigKey<Integer> Wait = new ConfigKey<Integer>(Integer.class, "wait", "Advance", "1800", protected final ConfigKey<Integer> Wait = new ConfigKey<Integer>(Integer.class, "wait", "Advance", "1800",
"Time in seconds to wait for control commands to return", true, "Seconds"); "Time in seconds to wait for control commands to return", true);
protected final ConfigKey<Integer> AlertWait = new ConfigKey<Integer>(Integer.class, "alert.wait", "Advance", "1800", protected final ConfigKey<Integer> AlertWait = new ConfigKey<Integer>(Integer.class, "alert.wait", "Advance", "1800",
"Seconds to wait before alerting on a disconnected agent", true, "Seconds"); "Seconds to wait before alerting on a disconnected agent", true);
protected final ConfigKey<Integer> DirectAgentLoadSize = new ConfigKey<Integer>(Integer.class, "direct.agent.load.size", "Advance", "16", protected final ConfigKey<Integer> DirectAgentLoadSize = new ConfigKey<Integer>(Integer.class, "direct.agent.load.size", "Advance", "16",
"The number of direct agents to load each time", false, null); "The number of direct agents to load each time", false, null);
protected final ConfigKey<Integer> DirectAgentPoolSize = new ConfigKey<Integer>(Integer.class, "direct.agent.pool.size", "Advance", "500", protected final ConfigKey<Integer> DirectAgentPoolSize = new ConfigKey<Integer>(Integer.class, "direct.agent.pool.size", "Advance", "500",

View File

@ -134,13 +134,13 @@ public class ClusteredAgentManagerImpl extends AgentManagerImpl implements Clust
} }
protected final ConfigKey<Boolean> EnableLB = new ConfigKey<Boolean>(Boolean.class, "agent.lb.enabled", "Advanced", "false", protected final ConfigKey<Boolean> EnableLB = new ConfigKey<Boolean>(Boolean.class, "agent.lb.enabled", "Advanced", "false",
"Enable agent load balancing between management server nodes", true, "True/False"); "Enable agent load balancing between management server nodes", true);
protected final ConfigKey<Double> ConnectedAgentThreshold = new ConfigKey<Double>(Double.class, "agent.load.threshold", "Advanced", "0.7", protected final ConfigKey<Double> ConnectedAgentThreshold = new ConfigKey<Double>(Double.class, "agent.load.threshold", "Advanced", "0.7",
"What percentage of the agents can be held by one management server before load balancing happens", true, "0-1"); "What percentage of the agents can be held by one management server before load balancing happens", true);
protected final ConfigKey<Integer> LoadSize = new ConfigKey<Integer>(Integer.class, "direct.agent.load.size", "Advanced", "16", protected final ConfigKey<Integer> LoadSize = new ConfigKey<Integer>(Integer.class, "direct.agent.load.size", "Advanced", "16",
"How many agents to connect to in each round", true, ""); "How many agents to connect to in each round", true);
protected final ConfigKey<Integer> ScanInterval = new ConfigKey<Integer>(Integer.class, "direct.agent.scan.interval", "Advanced", "90", protected final ConfigKey<Integer> ScanInterval = new ConfigKey<Integer>(Integer.class, "direct.agent.scan.interval", "Advanced", "90",
"Interval between scans to load agents", false, "Seconds"); "Interval between scans to load agents", false);
protected ConfigValue<Boolean> _agentLBEnabled; protected ConfigValue<Boolean> _agentLBEnabled;

View File

@ -46,6 +46,7 @@ import org.apache.commons.codec.binary.Base64;
import org.apache.commons.io.FileUtils; import org.apache.commons.io.FileUtils;
import org.apache.log4j.Logger; import org.apache.log4j.Logger;
import org.apache.cloudstack.framework.config.ConfigDepotAdmin;
import org.apache.cloudstack.framework.config.ConfigurationVO; import org.apache.cloudstack.framework.config.ConfigurationVO;
import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.config.dao.ConfigurationDao;
import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao; import org.apache.cloudstack.storage.datastore.db.PrimaryDataStoreDao;
@ -142,6 +143,8 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio
@Inject private ClusterDetailsDao _clusterDetailsDao; @Inject private ClusterDetailsDao _clusterDetailsDao;
@Inject private StoragePoolDetailsDao _storagePoolDetailsDao; @Inject private StoragePoolDetailsDao _storagePoolDetailsDao;
@Inject private AccountDetailsDao _accountDetailsDao; @Inject private AccountDetailsDao _accountDetailsDao;
@Inject
protected ConfigDepotAdmin _configDepotAdmin;
public ConfigurationServerImpl() { public ConfigurationServerImpl() {
setRunLevel(ComponentLifecycle.RUN_LEVEL_FRAMEWORK_BOOTSTRAP); setRunLevel(ComponentLifecycle.RUN_LEVEL_FRAMEWORK_BOOTSTRAP);
@ -153,6 +156,7 @@ public class ConfigurationServerImpl extends ManagerBase implements Configuratio
try { try {
persistDefaultValues(); persistDefaultValues();
_configDepotAdmin.populateConfigurations();
} catch (InternalErrorException e) { } catch (InternalErrorException e) {
throw new RuntimeException("Unhandled configuration exception", e); throw new RuntimeException("Unhandled configuration exception", e);
} }