Skip to content
Snippets Groups Projects
Commit fa4e8b16 authored by Rob Adams's avatar Rob Adams
Browse files

Add application-loading capability and create debian packages for bigtap and bvs applications

parent f1da026a
No related branches found
No related tags found
No related merge requests found
Showing
with 367 additions and 43 deletions
...@@ -277,7 +277,7 @@ ...@@ -277,7 +277,7 @@
</jar> </jar>
</target> </target>
<target name="package"> <!-- depends="dist" //--> <target name="deb" depends="dist">
<taskdef name="deb" <taskdef name="deb"
classname="org.vafer.jdeb.ant.DebAntTask" classname="org.vafer.jdeb.ant.DebAntTask"
classpathref="package-classpath"/> classpathref="package-classpath"/>
...@@ -311,11 +311,13 @@ ...@@ -311,11 +311,13 @@
<data src="debian/misc/default/floodlight" type="file"> <data src="debian/misc/default/floodlight" type="file">
<mapper type="perm" prefix="/etc/default"/> <mapper type="perm" prefix="/etc/default"/>
</data> </data>
<data src="src/main/resources/floodlightdefault.properties" type="file"> <data src="debian/misc/floodlight.properties" type="file">
<mapper type="perm" prefix="/etc/floodlight"/> <mapper type="perm" prefix="/etc/floodlight"/>
</data> </data>
<tarfileset dir="src/main/resources/apps" prefix="/etc/floodlight/apps.d"/>
</deb> </deb>
</target> </target>
<target name="package" depends="deb"/>
<target name="javadoc"> <target name="javadoc">
<javadoc access="protected" <javadoc access="protected"
......
/var/log/floodlight /var/log/floodlight
/var/lib/floodlight /var/lib/floodlight
/etc/floodlight/apps.d
/etc/floodlight/conf.d
#!/bin/sh -e #!/bin/sh -e
NAME=floodlight NAME=floodlight
KEYSTORE=/etc/floodlight/auth_credentials.jceks
case "$1" in case "$1" in
configure) configure)
...@@ -10,13 +11,23 @@ case "$1" in ...@@ -10,13 +11,23 @@ case "$1" in
fi fi
mkdir -p /var/log/floodlight mkdir -p /var/log/floodlight
mkdir -p /var/lib/floodlight mkdir -p /var/lib/floodlight
chown -R $NAME:$NAME /var/log/floodlight mkdir -p /etc/floodlight/conf.d
chown -R syslog:adm /var/log/floodlight
chown -R $NAME:$NAME /var/lib/floodlight chown -R $NAME:$NAME /var/lib/floodlight
if [ ! -f /etc/floodlight/auth_credentials.jceks ]; then if [ ! -f /etc/floodlight/auth_credentials.jceks ]; then
KSPASS=`dd if=/dev/urandom bs=1 count=32 2>/dev/null | base64 -w 0 | rev | cut -b 2- | rev`
echo "org.sdnplatform.sync.internal.SyncManager.keyStorePassword=$KSPASS" > \
/etc/floodlight/conf.d/01-keystorepass.properties
authtool -a CHALLENGE_RESPONSE \ authtool -a CHALLENGE_RESPONSE \
-ks /etc/floodlight/auth_credentials.jceks \ -ks $KEYSTORE \
-kp dcbc178a0a3a8674f048ac86372ac456 -kp $KSPASS
chown $NAME:$NAME $KEYSTORE
fi fi
service rsyslog reload
service floodlight restart
;; ;;
abort-upgrade|abort-remove|abort-deconfigure) abort-upgrade|abort-remove|abort-deconfigure)
......
...@@ -7,6 +7,7 @@ case "$1" in ...@@ -7,6 +7,7 @@ case "$1" in
deluser --quiet --system $NAME || true deluser --quiet --system $NAME || true
delgroup --quiet --system $NAME || true delgroup --quiet --system $NAME || true
rm -f /etc/floodlight/auth_credentials.jceks rm -f /etc/floodlight/auth_credentials.jceks
rm -f /etc/floodlight/conf.d/01-keystorepass.properties
rm -rf /var/lib/floodlight/SyncDB rm -rf /var/lib/floodlight/SyncDB
;; ;;
......
#!/bin/sh -e
NAME=floodlight
case "$1" in
purge)
rm -f /etc/floodlight/auth_credentials.jceks
rm -f /etc/floodlight/conf.d/01-keystorepass.properties
rm -rf /var/lib/floodlight/SyncDB
;;
remove)
service floodlight stop
;;
upgrade|failed-upgrade|abort-install|abort-upgrade|disappear)
;;
*)
echo "prerm called with unknown argument \`$1'" >&2
exit 1
;;
esac
#DEBHELPER#
exit 0
#!/bin/sh #!/bin/sh
exec java -cp /usr/share/floodlight/java/floodlight.jar org.sdnplatform.sync.client.AuthTool "$@" exec java -cp '/usr/share/floodlight/java/*' org.sdnplatform.sync.client.AuthTool "$@"
#!/bin/sh #!/bin/sh
exec java -cp /usr/share/floodlight/java/floodlight.jar org.sdnplatform.sync.client.BootstrapTool "$@" exec java -cp '/usr/share/floodlight/java/*' org.sdnplatform.sync.client.BootstrapTool "$@"
#!/bin/sh #!/bin/sh
exec java -cp /usr/share/floodlight/java/floodlight.jar net.floodlightcontroller.core.Main "$@" exec java -cp '/usr/share/floodlight/java/*' net.floodlightcontroller.core.Main "$@"
#!/bin/sh #!/bin/sh
exec java -cp /usr/share/floodlight/java/floodlight.jar org.sdnplatform.sync.client.SyncClient "$@" exec java -cp '/usr/share/floodlight/java/*' org.sdnplatform.sync.client.SyncClient "$@"
# Options to pass to Floodlight. # Options to pass to Floodlight.
DAEMON_OPTS="-cf /etc/floodlight/floodlightdefault.properties" DAEMON_OPTS="-cf /etc/floodlight/floodlight.properties"
# Additional options to pass to the JVM # Additional options to pass to the JVM
JVM_OPTS="" JVM_OPTS=""
# Sample performance options taken from upstream # Sample performance options taken from upstream
......
floodlight.confd = /etc/floodlight/conf.d
floodlight.modules = \
net.floodlightcontroller.jython.JythonDebugInterface,\
net.floodlightcontroller.core.module.ApplicationLoader
net.floodlightcontroller.core.module.ApplicationLoader.appsd=/etc/floodlight/apps.d
net.floodlightcontroller.core.module.ApplicationLoader.application=simpleforwarding
net.floodlightcontroller.core.FloodlightProvider.rolepath=/var/lib/floodlight/current_role
org.sdnplatform.sync.internal.SyncManager.authScheme=CHALLENGE_RESPONSE
org.sdnplatform.sync.internal.SyncManager.keyStorePath=/etc/floodlight/auth_credentials.jceks
org.sdnplatform.sync.internal.SyncManager.dbPath=/var/lib/floodlight/
...@@ -9,6 +9,6 @@ script ...@@ -9,6 +9,6 @@ script
if [ -f /etc/default/floodlight ]; then if [ -f /etc/default/floodlight ]; then
. /etc/default/floodlight . /etc/default/floodlight
fi fi
COMMAND="java ${JVM_OPTS} -cp /usr/share/floodlight/java/floodlight.jar net.floodlightcontroller.core.Main ${DAEMON_OPTS}" COMMAND="java ${JVM_OPTS} -cp '/usr/share/floodlight/java/*' net.floodlightcontroller.core.Main ${DAEMON_OPTS}"
exec /bin/bash -c "${COMMAND} 2>&1 | /usr/bin/logger -t floodlight -p user.info" exec /bin/bash -c "${COMMAND} 2>&1 | /usr/bin/logger -t floodlight -p user.info"
end script end script
!floodlight !floodlight
*.* /var/log/floodlight.log *.* /var/log/floodlight/floodlight.log
!* !*
package net.floodlightcontroller.core.module;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.ObjectReader;
/**
* Load an application from a configuration directory
* @author readams
*/
public class ApplicationLoader
implements IFloodlightModule, IApplicationService {
/**
* Representation for the application configuration
* @author readams
*/
public static class Application {
private String name;
private String[] modules;
private Map<String,String> config;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String[] getModules() {
return modules;
}
public void setModules(String[] modules) {
this.modules = modules;
}
public Map<String, String> getConfig() {
return config;
}
public void setConfig(Map<String, String> config) {
this.config = config;
}
}
protected static Logger logger =
LoggerFactory.getLogger(ApplicationLoader.class);
protected static ObjectMapper mapper = new ObjectMapper();
protected static ObjectReader reader = mapper.reader(Application.class);
IModuleService moduleService;
private static String APP_RESOURCE_PATH = "apps/";
/**
* Path containing application description files
*/
protected String applicationPath;
/**
* Application to load
*/
protected String application;
// *****************
// IFloodlightModule
// *****************
@Override
public Collection<Class<? extends IFloodlightService>>
getModuleServices() {
Collection<Class<? extends IFloodlightService>> l =
new ArrayList<Class<? extends IFloodlightService>>();
l.add(IApplicationService.class);
return l;
}
@Override
public Map<Class<? extends IFloodlightService>, IFloodlightService>
getServiceImpls() {
Map<Class<? extends IFloodlightService>,
IFloodlightService> m =
new HashMap<Class<? extends IFloodlightService>,
IFloodlightService>();
// We are the class that implements the service
m.put(IApplicationService.class, this);
return m;
}
@Override
public Collection<Class<? extends IFloodlightService>>
getModuleDependencies() {
return null;
}
@Override
public void init(FloodlightModuleContext context)
throws FloodlightModuleException {
moduleService = context.getServiceImpl(IModuleService.class);
Map<String,String> config = context.getConfigParams(this);
if (config.containsKey("appsd"))
applicationPath = config.get("appsd");
if (config.containsKey("application"))
application = config.get("application");
}
@Override
public void startUp(FloodlightModuleContext context)
throws FloodlightModuleException {
if (application == null) {
throw new FloodlightModuleException("No application to load");
}
// attempt to load from application path
File appPath;
if (applicationPath != null &&
(appPath = new File(applicationPath)).exists() &&
appPath.isDirectory()) {
File[] files = appPath.listFiles();
Arrays.sort(files);
for (File f : files) {
if (f.isFile() && f.getName().matches(".*\\.json$"));
try {
if (loadApplication(new FileInputStream(f), f.getPath()))
return;
} catch (FileNotFoundException e) {
throw new FloodlightModuleException(e);
}
}
}
// attempt to load from classpath. Note here that the file needs
// to be named after the application to be successful
try {
String r = APP_RESOURCE_PATH + application + ".json";
InputStream is = getClass().getClassLoader().getResourceAsStream(r);
loadApplication(is, "resource: " + r);
} catch (Exception e) {
throw new FloodlightModuleException(e);
}
}
private boolean loadApplication(InputStream is, String path)
throws FloodlightModuleException {
Application a;
try {
a = reader.readValue(is);
} catch (Exception e) {
throw new FloodlightModuleException("Could not read application " +
path, e);
}
if (application.equals(a.getName())) {
Properties p = new Properties();
if (a.getConfig() != null)
p.putAll(a.getConfig());
if (a.getModules() != null) {
logger.info("Loading application {}", a.getName());
moduleService.loadModulesFromList(Arrays.asList(a.getModules()),
p);
return true;
}
}
return false;
}
}
...@@ -16,6 +16,7 @@ ...@@ -16,6 +16,7 @@
package net.floodlightcontroller.core.module; package net.floodlightcontroller.core.module;
import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.HashMap; import java.util.HashMap;
import java.util.Map; import java.util.Map;
...@@ -69,8 +70,10 @@ public class FloodlightModuleContext implements IFloodlightModuleContext { ...@@ -69,8 +70,10 @@ public class FloodlightModuleContext implements IFloodlightModuleContext {
return moduleSet; return moduleSet;
} }
public void setModuleSet(Collection<IFloodlightModule> modSet) { public void addModules(Collection<IFloodlightModule> modSet) {
this.moduleSet = modSet; if (this.moduleSet == null)
this.moduleSet = new ArrayList<IFloodlightModule>();
this.moduleSet.addAll(modSet);
} }
@Override @Override
......
...@@ -18,7 +18,6 @@ package net.floodlightcontroller.core.module; ...@@ -18,7 +18,6 @@ package net.floodlightcontroller.core.module;
import java.io.File; import java.io.File;
import java.io.FileInputStream; import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays; import java.util.Arrays;
...@@ -47,7 +46,7 @@ import org.slf4j.LoggerFactory; ...@@ -47,7 +46,7 @@ import org.slf4j.LoggerFactory;
* @author alexreimers * @author alexreimers
* *
*/ */
public class FloodlightModuleLoader { public class FloodlightModuleLoader implements IModuleService {
protected static Logger logger = protected static Logger logger =
LoggerFactory.getLogger(FloodlightModuleLoader.class); LoggerFactory.getLogger(FloodlightModuleLoader.class);
...@@ -58,6 +57,9 @@ public class FloodlightModuleLoader { ...@@ -58,6 +57,9 @@ public class FloodlightModuleLoader {
IFloodlightService>>> moduleServiceMap; IFloodlightService>>> moduleServiceMap;
protected static Map<String, IFloodlightModule> moduleNameMap; protected static Map<String, IFloodlightModule> moduleNameMap;
protected static Object lock = new Object(); protected static Object lock = new Object();
protected static Set<String> initedSet = new HashSet<String>();
protected static Set<String> startedSet = new HashSet<String>();;
protected FloodlightModuleContext floodlightModuleContext; protected FloodlightModuleContext floodlightModuleContext;
...@@ -65,9 +67,12 @@ public class FloodlightModuleLoader { ...@@ -65,9 +67,12 @@ public class FloodlightModuleLoader {
"floodlightdefault.properties"; "floodlightdefault.properties";
public static final String FLOODLIGHT_MODULES_KEY = public static final String FLOODLIGHT_MODULES_KEY =
"floodlight.modules"; "floodlight.modules";
public static final String FLOODLIGHT_CONFD =
"floodlight.confd";
public FloodlightModuleLoader() { public FloodlightModuleLoader() {
floodlightModuleContext = new FloodlightModuleContext(); floodlightModuleContext = new FloodlightModuleContext();
floodlightModuleContext.addService(IModuleService.class, this);
} }
/** /**
...@@ -180,33 +185,62 @@ public class FloodlightModuleLoader { ...@@ -180,33 +185,62 @@ public class FloodlightModuleLoader {
public IFloodlightModuleContext loadModulesFromConfig(String fName) public IFloodlightModuleContext loadModulesFromConfig(String fName)
throws FloodlightModuleException { throws FloodlightModuleException {
Properties prop = new Properties(); Properties prop = new Properties();
Collection<String> configMods;
File f = new File(fName); File f = new File(fName);
if (f.isFile()) { if (f.isFile()) {
logger.info("Loading modules from file {}", fName); logger.info("Loading modules from file {}", f.getPath());
try { configMods = loadProperties(null, f, prop);
prop.load(new FileInputStream(fName));
} catch (Exception e) {
logger.error("Could not load module configuration file", e);
System.exit(1);
}
} else { } else {
logger.info("Loading default modules"); logger.info("Loading default modules");
InputStream is = this.getClass().getClassLoader(). InputStream is = this.getClass().getClassLoader().
getResourceAsStream(COMPILED_CONF_FILE); getResourceAsStream(COMPILED_CONF_FILE);
try { configMods = loadProperties(is, null, prop);
prop.load(is); }
} catch (IOException e) {
logger.error("Could not load default modules", e); return loadModulesFromList(configMods, prop);
System.exit(1); }
private Collection<String> loadProperties(InputStream is,
File confFile,
Properties prop) {
try {
Properties fprop = new Properties();
if (is != null) {
fprop.load(is);
} else {
fprop.load(new FileInputStream(confFile));
} }
prop.putAll(fprop);
} catch (Exception e) {
logger.error("Could not load module configuration file", e);
System.exit(1);
} }
String moduleList = prop.getProperty(FLOODLIGHT_MODULES_KEY)
.replaceAll("\\s", "");
Collection<String> configMods = new ArrayList<String>(); Collection<String> configMods = new ArrayList<String>();
configMods.addAll(Arrays.asList(moduleList.split(","))); String moduleList = prop.getProperty(FLOODLIGHT_MODULES_KEY);
return loadModulesFromList(configMods, prop); if (moduleList != null) {
moduleList = moduleList.replaceAll("\\s", "");
configMods.addAll(Arrays.asList(moduleList.split(",")));
prop.remove(FLOODLIGHT_MODULES_KEY);
}
String confdStr = prop.getProperty(FLOODLIGHT_CONFD);
prop.remove(FLOODLIGHT_CONFD);
if (confdStr != null) {
File confd = new File(confdStr);
if (confd.exists() && confd.isDirectory()) {
File[] files = confd.listFiles();
Arrays.sort(files);
for (File f : files) {
if (f.isFile() &&
f.getName().matches(".*\\.properties$"))
configMods.addAll(loadProperties(null, f, prop));
}
}
}
return configMods;
} }
/** /**
...@@ -245,7 +279,7 @@ public class FloodlightModuleLoader { ...@@ -245,7 +279,7 @@ public class FloodlightModuleLoader {
throw new FloodlightModuleException("Module " + throw new FloodlightModuleException("Module " +
moduleName + " not found"); moduleName + " not found");
} }
// If the module provies a service that is in the // If the module provides a service that is in the
// services ignorelist don't load it. // services ignorelist don't load it.
if ((ignoreList != null) && (module.getModuleServices() != null)) { if ((ignoreList != null) && (module.getModuleServices() != null)) {
for (IFloodlightService ifs : ignoreList) { for (IFloodlightService ifs : ignoreList) {
...@@ -315,7 +349,7 @@ public class FloodlightModuleLoader { ...@@ -315,7 +349,7 @@ public class FloodlightModuleLoader {
} }
} }
floodlightModuleContext.setModuleSet(moduleSet); floodlightModuleContext.addModules(moduleSet);
parseConfigParameters(prop); parseConfigParameters(prop);
initModules(moduleSet); initModules(moduleSet);
startupModules(moduleSet); startupModules(moduleSet);
...@@ -323,13 +357,7 @@ public class FloodlightModuleLoader { ...@@ -323,13 +357,7 @@ public class FloodlightModuleLoader {
return floodlightModuleContext; return floodlightModuleContext;
} }
/** @Override
* Loads modules (and their dependencies) specified in the list.
* @param configMods The collection of fully qualified module names to load.
* @param prop The list of properties that are configuration options.
* @return The ModuleContext containing all the loaded modules.
* @throws FloodlightModuleException
*/
public IFloodlightModuleContext loadModulesFromList(Collection<String> configMods, Properties prop) public IFloodlightModuleContext loadModulesFromList(Collection<String> configMods, Properties prop)
throws FloodlightModuleException { throws FloodlightModuleException {
return loadModulesFromList(configMods, prop, null); return loadModulesFromList(configMods, prop, null);
...@@ -363,7 +391,10 @@ public class FloodlightModuleLoader { ...@@ -363,7 +391,10 @@ public class FloodlightModuleLoader {
*/ */
protected void initModules(Collection<IFloodlightModule> moduleSet) protected void initModules(Collection<IFloodlightModule> moduleSet)
throws FloodlightModuleException { throws FloodlightModuleException {
for (IFloodlightModule module : moduleSet) { for (IFloodlightModule module : moduleSet) {
if (initedSet.contains(module.getClass().getCanonicalName()))
continue;
// Get the module's service instance(s) // Get the module's service instance(s)
Map<Class<? extends IFloodlightService>, Map<Class<? extends IFloodlightService>,
IFloodlightService> simpls = module.getServiceImpls(); IFloodlightService> simpls = module.getServiceImpls();
...@@ -394,6 +425,10 @@ public class FloodlightModuleLoader { ...@@ -394,6 +425,10 @@ public class FloodlightModuleLoader {
} }
for (IFloodlightModule module : moduleSet) { for (IFloodlightModule module : moduleSet) {
if (initedSet.contains(module.getClass().getCanonicalName()))
continue;
initedSet.add(module.getClass().getCanonicalName());
// init the module // init the module
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Initializing " + logger.debug("Initializing " +
...@@ -411,6 +446,10 @@ public class FloodlightModuleLoader { ...@@ -411,6 +446,10 @@ public class FloodlightModuleLoader {
protected void startupModules(Collection<IFloodlightModule> moduleSet) protected void startupModules(Collection<IFloodlightModule> moduleSet)
throws FloodlightModuleException { throws FloodlightModuleException {
for (IFloodlightModule m : moduleSet) { for (IFloodlightModule m : moduleSet) {
if (startedSet.contains(m.getClass().getCanonicalName()))
continue;
startedSet.add(m.getClass().getCanonicalName());
if (logger.isDebugEnabled()) { if (logger.isDebugEnabled()) {
logger.debug("Starting " + m.getClass().getCanonicalName()); logger.debug("Starting " + m.getClass().getCanonicalName());
} }
......
package net.floodlightcontroller.core.module;
public interface IApplicationService extends IFloodlightService {
}
package net.floodlightcontroller.core.module;
import java.util.Collection;
import java.util.Properties;
public interface IModuleService extends IFloodlightService {
/**
* Loads modules (and their dependencies) specified in the list.
* @param configMods The collection of fully qualified module names to load.
* @param prop The list of properties that are configuration options.
* @return The ModuleContext containing all the loaded modules.
* @throws FloodlightModuleException
*/
public IFloodlightModuleContext
loadModulesFromList(Collection<String> configMods,
Properties prop) throws FloodlightModuleException;
}
net.floodlightcontroller.core.module.ApplicationLoader
net.floodlightcontroller.core.internal.FloodlightProvider net.floodlightcontroller.core.internal.FloodlightProvider
net.floodlightcontroller.storage.memory.MemoryStorageSource net.floodlightcontroller.storage.memory.MemoryStorageSource
net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl
......
{
"name": "simpleforwarding",
"modules": [
"net.floodlightcontroller.counter.CounterStore",
"net.floodlightcontroller.storage.memory.MemoryStorageSource",
"net.floodlightcontroller.core.internal.FloodlightProvider",
"net.floodlightcontroller.threadpool.ThreadPool",
"net.floodlightcontroller.devicemanager.internal.DeviceManagerImpl",
"net.floodlightcontroller.devicemanager.internal.DefaultEntityClassifier",
"net.floodlightcontroller.staticflowentry.StaticFlowEntryPusher",
"net.floodlightcontroller.firewall.Firewall",
"net.floodlightcontroller.forwarding.Forwarding",
"net.floodlightcontroller.linkdiscovery.internal.LinkDiscoveryManager",
"net.floodlightcontroller.topology.TopologyManager",
"net.floodlightcontroller.flowcache.FlowCache",
"net.floodlightcontroller.flowcache.FlowReconcileManager",
"net.floodlightcontroller.debugcounter.DebugCounter",
"net.floodlightcontroller.perfmon.PktInProcessingTime",
"net.floodlightcontroller.ui.web.StaticWebRoutable",
"net.floodlightcontroller.loadbalancer.LoadBalancer",
"org.sdnplatform.sync.internal.SyncManager"
],
"config": {
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment