Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
#114: poc for plugin mechanism
  • Loading branch information
ypujante committed Dec 14, 2011
1 parent 805c08d commit a31f6a6
Show file tree
Hide file tree
Showing 11 changed files with 402 additions and 21 deletions.
Expand Up @@ -29,12 +29,15 @@ import org.linkedin.glu.console.domain.DbUserCredentials
import org.linkedin.glu.orchestration.engine.system.SystemService
import org.linkedin.glu.orchestration.engine.delta.DeltaService
import org.linkedin.glu.orchestration.engine.delta.CustomDeltaDefinition
import org.linkedin.glu.orchestration.engine.plugins.PluginServiceImpl
import org.codehaus.groovy.grails.commons.ApplicationHolder

class BootStrap {

ConsoleConfig consoleConfig
SystemService systemService
DeltaService deltaService
PluginServiceImpl pluginService

def init = { servletContext ->
log.info "Starting up... [${Environment.current} mode]"
Expand All @@ -56,6 +59,16 @@ class BootStrap {
log.warn "console.ivySettingsURL config parameter not specified, ivy:/ URLhandler is not enabled."
}

// initializing the plugin if one is provided
if(consoleConfig.defaults.plugins?.engine)
{
pluginService.initializePlugin(consoleConfig.defaults.plugins.engine,
[
applicationContext: ApplicationHolder.application.mainContext,
defaults: consoleConfig.defaults
])
}

// setting up data when development...
if(Environment.current == Environment.DEVELOPMENT)
{
Expand Down
Expand Up @@ -155,6 +155,10 @@ console.dev.defaults =
'glu-dev-1': ['drMode': 'primary'],
'glu-dev-2': ['drMode': 'secondary']
],

// plugins: [
// engine: 'org.linkedin.glu.console.provisioner.services.MyPlugin'
// ]
]

// set per-environment serverURL stem for creating absolute links
Expand Down
Expand Up @@ -203,6 +203,7 @@
<property name="deploymentStorage">
<bean class="org.linkedin.glu.console.provisioner.services.storage.DeploymentStorageImpl"/>
</property>
<property name="pluginService" ref="pluginService"/>
<property name="autoArchiveTimeout">
<bean class="org.linkedin.util.clock.Timespan" factory-method="parse">
<constructor-arg value="${console.deploymentService.autoArchiveTimeout}"/>
Expand Down Expand Up @@ -251,4 +252,9 @@
<bean id="encryptionService" class="org.linkedin.glu.orchestration.engine.encryption.EncryptionServiceImpl">
<property name="encryptionKeysProvider" ref="encryptionKeysProvider"/>
</bean>

<!-- *********************** -->
<!-- pluginService -->
<!-- *********************** -->
<bean id="pluginService" class="org.linkedin.glu.orchestration.engine.plugins.PluginServiceImpl"/>
</beans>
Expand Up @@ -37,6 +37,7 @@ import org.linkedin.glu.orchestration.engine.action.descriptor.ActionDescriptor
import org.linkedin.groovy.util.json.JsonUtils
import org.linkedin.glu.orchestration.engine.deployment.ArchivedDeployment
import org.linkedin.glu.orchestration.engine.deployment.Deployment
import java.security.AccessControlException

/**
* @author ypujante@linkedin.com */
Expand Down Expand Up @@ -102,15 +103,22 @@ public class PlanController extends ControllerBase

if(plan)
{
session.plan = null

CurrentDeployment currentDeployment =
deploymentService.executeDeploymentPlan(request.system,
plan,
plan.name,
new ProgressTracker())

redirect(action: 'deployments', id: currentDeployment.id)
try
{
CurrentDeployment currentDeployment =
deploymentService.executeDeploymentPlan(request.system,
plan,
plan.name,
new ProgressTracker())
session.plan = null
redirect(action: 'deployments', id: currentDeployment.id)
}
catch (AccessControlException e)
{
flash.error = e.message
redirect(action: 'view', id: params.id)
return
}
}
else
{
Expand Down
Expand Up @@ -87,9 +87,9 @@ interface DeploymentService

boolean isExecutingDeploymentPlan(String fabric)

CurrentDeployment executeDeploymentPlan(SystemModel system, Plan plan)
CurrentDeployment executeDeploymentPlan(SystemModel model, Plan plan)

CurrentDeployment executeDeploymentPlan(SystemModel system,
CurrentDeployment executeDeploymentPlan(SystemModel model,
Plan plan,
String description,
IPlanExecutionProgressTracker progressTracker)
Expand Down
Expand Up @@ -31,6 +31,7 @@ import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.linkedin.groovy.util.clock.ClosureTimerTask
import org.linkedin.glu.provisioner.plan.api.IStepCompletionStatus
import org.linkedin.glu.orchestration.engine.plugins.PluginService

/**
* System service.
Expand Down Expand Up @@ -68,6 +69,9 @@ class DeploymentServiceImpl implements DeploymentService, Startable, Destroyable
@Initializable
AuthorizationService authorizationService

@Initializable
PluginService pluginService

private Map<String, CurrentDeployment> _deployments = [:]
private Map<String, Plan> _plans = [:]

Expand Down Expand Up @@ -267,34 +271,44 @@ class DeploymentServiceImpl implements DeploymentService, Startable, Destroyable
executeDeploymentPlan(system, plan, plan.name, null)
}

CurrentDeployment executeDeploymentPlan(SystemModel system,
CurrentDeployment executeDeploymentPlan(SystemModel model,
Plan plan,
String description,
IPlanExecutionProgressTracker progressTracker)
{
pluginService?.executeMethod(DeploymentService,
"pre_executeDeploymentPlan",
[
model: model,
plan: plan,
description: description
])

synchronized(_deployments)
{
String username = authorizationService?.getExecutingPrincipal()

ArchivedDeployment deployment =
deploymentStorage.startDeployment(description,
system.fabric,
model.fabric,
username,
plan.toXml())

def id = deployment.id

def tracker = new ProgressTracker(deploymentStorage,
pluginService,
progressTracker,
id,
system)
model,
description)

def planExecution = deployer.executePlan(plan, tracker)

CurrentDeployment currentDeployment = new CurrentDeployment(id: id,
username: username,
fabric: system.fabric,
systemId: system.id,
fabric: model.fabric,
systemId: model.id,
planExecution: planExecution,
description: description,
progressTracker: progressTracker)
Expand Down
Expand Up @@ -21,25 +21,32 @@ import org.linkedin.glu.provisioner.core.model.SystemModel
import org.linkedin.glu.provisioner.plan.api.FilteredPlanExecutionProgressTracker
import org.linkedin.glu.provisioner.plan.api.IPlanExecution
import org.linkedin.glu.provisioner.plan.api.IStepCompletionStatus
import org.linkedin.glu.orchestration.engine.plugins.PluginService

/**
* @author yan@pongasoft.com */
class ProgressTracker<T> extends FilteredPlanExecutionProgressTracker<T>
{
final DeploymentStorage _deploymentStorage
final PluginService _pluginService
def final _deploymentId
private IPlanExecution _planExecution
private final SystemModel _system
private final SystemModel _model
private final String _description

def ProgressTracker(DeploymentStorage deploymentStorage,
PluginService pluginService,
tracker,
deploymentId,
SystemModel system)
SystemModel model,
String description)
{
super(tracker)
_deploymentStorage = deploymentStorage
_pluginService = pluginService
_deploymentId = deploymentId
_system = system
_model = model
_description = description
}

public void onPlanStart(IPlanExecution<T> planExecution)
Expand All @@ -52,7 +59,16 @@ class ProgressTracker<T> extends FilteredPlanExecutionProgressTracker<T>
public void onPlanEnd(IStepCompletionStatus<T> status)
{
super.onPlanEnd(status)
String details = _planExecution.toXml([fabric: _system.fabric, systemId: _system.id])
String details = _planExecution.toXml([fabric: _model.fabric, systemId: _model.id])
_deploymentStorage.endDeployment(_deploymentId, status, details)
_pluginService?.executeMethod(DeploymentService,
"post_executeDeploymentPlan",
[
model: _model,
plan: _planExecution.plan,
description: _description,

serviceResult: _planExecution
])
}
}
@@ -0,0 +1,33 @@
/*
* Copyright (c) 2011 Yan Pujante
*
* Licensed 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.linkedin.glu.orchestration.engine.plugins

/**
* @author yan@pongasoft.com */
public interface PluginService
{
void initializePlugin(String pluginClassname, Map initParameters)

void initializePlugin(Map plugin, Map initParameters)

void executeMethod(Class targetService, String pluginMethod, Map pluginArgs)

def executePrePostMethods(Class targetService,
String pluginMethod,
Map pluginArgs,
Closure serviceClosure)
}
@@ -0,0 +1,106 @@
/*
* Copyright (c) 2011 Yan Pujante
*
* Licensed 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.linkedin.glu.orchestration.engine.plugins

import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.linkedin.util.reflect.ReflectUtils

/**
* @author yan@pongasoft.com */
public class PluginServiceImpl implements PluginService
{
public static final String MODULE = PluginService.class.getName();
public static final Logger log = LoggerFactory.getLogger(MODULE);

def plugin

@Override
void initializePlugin(String pluginClassname, Map initParameters)
{
if(pluginClassname)
{
log.info("Initializing plugin [${pluginClassname}]")
plugin = ReflectUtils.forName(pluginClassname).newInstance()
executeMethod(PluginService, 'initialize', initParameters)
}
}

@Override
void initializePlugin(Map plugin, Map initParameters)
{
log.info("Initializing plugin from map")
this.plugin = plugin
executeMethod(PluginService, 'initialize', initParameters)
}

@Override
void executeMethod(Class targetService, String pluginMethod, Map pluginArgs)
{
executePluginClosure("${targetService.simpleName}_${pluginMethod}", pluginArgs)
}

@Override
def executePrePostMethods(Class targetService,
String pluginMethod,
Map pluginArgs,
Closure serviceClosure)
{
executePluginClosure("${targetService.simpleName}_pre_${pluginMethod}", pluginArgs)

try
{
def res = serviceClosure()

def args = [:]
if(pluginArgs)
args.putAll(pluginArgs)
args.serviceResult = res
executePluginClosure("${targetService.simpleName}_post_${pluginMethod}",
args)
return res
}
catch(Throwable th)
{
def args = [:]
if(pluginArgs)
args.putAll(pluginArgs)
args.serviceException = th
executePluginClosure("${targetService.simpleName}_post_${pluginMethod}",
args)
throw th
}
}

private void executePluginClosure(String closureName, Map pluginArgs)
{
def closure = null

if(plugin instanceof Map)
{
closure = plugin[closureName]
}
else
{
if(plugin?.hasProperty(closureName))
closure = plugin."${closureName}"
}

if(closure)
closure(pluginArgs)
}
}

0 comments on commit a31f6a6

Please sign in to comment.