All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.linkedin.glu.agent.impl.AgentImpl.groovy Maven / Gradle / Ivy

/*
 * Copyright (c) 2010-2010 LinkedIn, Inc
 * Portions 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.agent.impl

import org.linkedin.glu.agent.api.Agent
import org.linkedin.glu.agent.impl.script.AgentContext
import org.linkedin.glu.agent.api.Shell

import org.linkedin.glu.agent.api.MountPoint
import org.linkedin.glu.agent.impl.script.ScriptManagerImpl
import org.linkedin.glu.agent.impl.script.ScriptManager
import org.linkedin.glu.agent.impl.script.StateKeeperScriptManager

import org.hyperic.sigar.Sigar
import org.hyperic.sigar.SigarException
import org.linkedin.glu.agent.api.AgentException
import java.util.concurrent.TimeoutException
import org.linkedin.util.lifecycle.Shutdownable

import org.linkedin.util.io.resource.Resource
import org.linkedin.util.clock.Timespan
import org.linkedin.glu.agent.api.TimeOutException
import org.linkedin.glu.utils.tags.Taggeable
import org.linkedin.glu.utils.tags.TaggeableTreeSetImpl
import org.linkedin.glu.agent.impl.script.ScriptNode
import java.util.concurrent.ExecutionException
import org.linkedin.glu.agent.impl.command.CommandManager
import org.linkedin.glu.agent.impl.command.CommandManagerImpl
import org.linkedin.glu.agent.api.NoSuchCommandException
import org.linkedin.glu.commands.impl.MemoryCommandExecutionIOStorage
import org.linkedin.glu.commands.impl.CommandExecution
import org.linkedin.glu.agent.impl.command.CommandGluScriptFactoryFactory
import org.linkedin.glu.agent.impl.script.AgentContextImpl
import org.linkedin.glu.agent.impl.capabilities.MOPImpl
import org.linkedin.util.clock.SystemClock

/**
 * The main implementation of the agent
 */
def class AgentImpl implements Agent, AgentContext, Shutdownable
{
  public static final String MODULE = AgentImpl.class.getName();
  public static final org.slf4j.Logger log = org.slf4j.LoggerFactory.getLogger(MODULE);

  private @Delegate AgentContext _agentContext
  private Sigar _sigar
  private Shell _rootShell
  private Resource _agentLogDir
  private ScriptManager _scriptManager
  private CommandManager _commandManager
  private Closure _sync
  private Taggeable _taggeable

  private volatile _shutdown = false

  /********************************************************************
   * Boot
   ********************************************************************/
  /**
   * Boots the agent.
   *
   * 
    *
  • restartSoftware: the flag indicates whether the software that were running * before the agent was shutdown should be started again (default to false)
  • *
*/ void boot(args) { _rootShell = args.rootShell _agentContext = args.agentContext ?: new AgentContextImpl(clock: args.clock ?: SystemClock.INSTANCE, shellForScripts: args.shellForScripts, shellForCommands: args.shellForCommands ?: _rootShell, rootShell: _rootShell, mop: new MOPImpl()) _agentLogDir = args.agentLogDir _sigar = args.sigar def storage = args.storage if(storage != null) { _scriptManager = new ScriptManagerImpl(agentContext: _agentContext) _commandManager = new CommandManagerImpl(agentContext: _agentContext, ioStorage: new MemoryCommandExecutionIOStorage(clock: clock)) def f = new CommandGluScriptFactoryFactory(ioStorage: _commandManager.ioStorage) _scriptManager.scriptFactoryFactory.chain(f) _scriptManager = new StateKeeperScriptManager(scriptManager: _scriptManager, storage: storage) _commandManager.scriptManager = _scriptManager } else { _scriptManager = args.scriptManager _commandManager = args.commandManager } if(_scriptManager instanceof StateKeeperScriptManager) _scriptManager.restoreScripts() if(!_scriptManager.isMounted(MountPoint.ROOT)) _scriptManager.installRootScript([:]) _sync = args.sync _taggeable = args.taggeable ?: new TaggeableTreeSetImpl() } /** * Default shutdown: stops the containers and shut downs the agent * * @see #shutdown(boolean) */ void shutdown() { if(!_shutdown) { _shutdown = true _scriptManager.shutdown() } } /** * Shuts down the agent * * @param stopSoftware true if the software should be stopped or * false if it should be left running. */ void shutdown(boolean stopSoftware) { shutdown() } /** * Waits for the agent to be completely down (but no longer than the timeout). * @return true if it shutdown or false if the timeout elapsed before * termination */ void waitForShutdown(timeout) { if(!_shutdown) throw new IllegalStateException('call shutdown first!') timeout = Timespan.parse(timeout?.toString()) ?: Timespan.ZERO_MILLISECONDS _scriptManager.waitForShutdown(timeout.durationInMilliseconds) } public void waitForShutdown() { waitForShutdown(0) } public getMountPoints() { handleException { return _scriptManager.mountPoints } } /** * {@inheritdoc} */ public def getHostInfo() { handleException { log.info "getHostInfo()" def res = [:] if(_sigar) { // cpus res.cpus = _sigar.cpuInfoList?.collect { it.toMap() } // memory res.mem = _sigar.mem.toMap() } return res } } /** * {@inheritdoc} */ public def ps() { handleException { log.info "ps()" def ps = [:] def procList = _sigar?.procList ?: [] procList.each { pid -> def proc = [:] ps[pid] = proc [ 'env': 'getProcEnv', 'args': 'getProcArgs', 'cpu': 'getProcCpu', // 'cred': 'getProcCred', 'credName': 'getProcCredName', 'exe': 'getProcExe', 'fd': 'getProcFd', 'mem': 'getProcMem', 'modules': 'getProcModules', 'state': 'getProcState', 'time': 'getProcTime' ].each { k, v -> try { def res = _sigar."${v}"(pid) if(res.respondsTo('toMap')) res = res.toMap() proc[k] = res } catch (SigarException e) { if(log.isDebugEnabled()) log.debug("ignored exception", e) } } } return ps } } /** * {@inheritdoc} */ public void kill(long pid, int signal) { handleException { try { log.info "Sending signal ${signal} to process ${pid}" _sigar?.kill(pid, signal) } catch (SigarException e) { log.warn("Exception while sending signal ${signal} to process ${pid} (ignored)", e) throw new AgentException(e) } } } /** * {@inheritdoc} */ public void sync() { handleException { log.info "sync()" if(_sync) _sync() } } /** * {@inheritdoc} */ void installScript(args) { handleException { if(log.isDebugEnabled()) log.debug("installScript(${args})") _scriptManager.installScript(args) } } /** * {@inheritdoc} */ void uninstallScript(args) { handleException { if(log.isDebugEnabled()) log.debug("uninstallScript(${args})") def force = args.force != null ? args.force : false if(force instanceof String) force = Boolean.parseBoolean(force) if(force) interruptAction(args) _scriptManager.uninstallScript(args.mountPoint, force) } } /** * {@inheritdoc} */ String executeAction(args) { handleException { if(log.isDebugEnabled()) { log.debug("executeAction(" + args + ")") } _scriptManager.executeAction(args).id } } /** * {@inheritdoc} */ def waitForAction(args) { handleException { if(log.isDebugEnabled()) log.debug("waitForAction(${args})") _scriptManager.waitForAction(args) } } /** * {@inheritdoc} */ def executeActionAndWait(args) { handleException { if(log.isDebugEnabled()) log.debug("executeActionAndWait(${args})") def future = _scriptManager.executeAction(args) def timeout = Timespan.parse(args.timeout?.toString()) ?: Timespan.ZERO_MILLISECONDS try { def res = future.get(timeout) if(log.isDebugEnabled()) { if(res instanceof InputStream) log.debug("executeActionAndWait(${args}): InputStream") else log.debug("executeActionAndWait(${args}): ${res}") } return res } catch(ExecutionException e) { throw e.cause } catch (TimeoutException e) { if(log.isDebugEnabled()) log.debug("executeActionAndWait(${args}): TimeoutException[${e.message}]") throw new TimeoutException() } } } /* * {@inheritdoc} */ boolean interruptAction(args) { handleException { if(log.isDebugEnabled()) log.debug("interruptAction(${args})") _scriptManager.interruptAction(args) } } /** * {@inheritdoc} */ void clearError(args) { handleException { if(log.isDebugEnabled()) log.debug("clearError(" + args + ")") _scriptManager.clearError(MountPoint.create(args.mountPoint)) } } /** * {@inheritdoc} */ def executeCall(args) { handleException { if(log.isDebugEnabled()) log.debug("executeCall(" + args + ")") return _scriptManager.executeCall(args) } } /** * {@inheritdoc} */ public getState(args) { handleException { if(log.isDebugEnabled()) log.debug("getState(" + args + ")") return _scriptManager.getState(args.mountPoint) } } /** * {@inheritdoc} */ public getFullState(args) { handleException { if(log.isDebugEnabled()) log.debug("getFullState(" + args + ")") return _scriptManager.getFullState(args.mountPoint); } } /** * {@inheritdoc} */ boolean waitForState(args) { handleException { if(log.isDebugEnabled()) log.debug("waitForState(${args})") return _scriptManager.waitForState(args) } } /** * {@inheritdoc} */ boolean executeActionAndWaitForState(Object args) { executeAction(args) return waitForState(args); } /** * {@inheritdoc} */ InputStream tailAgentLog(args) { handleException { args.location = _agentLogDir.createRelative(args.log?.toString() ?: "${_rootShell.env['org.linkedin.app.name']}.out") getFileContent(args) } } /** * {@inheritdoc} */ def getFileContent(args) throws IOException, AgentException { handleException { log.info "getFileContent: ${args}" def location = _rootShell.toResource(args.location) if(location.isDirectory()) { def resources = _rootShell.ls(location) def res = [:] resources.each { def file = it.file def details = [:] res[file.name] = details details.canonicalPath = file.canonicalPath details.length = file.length() details.lastModified = file.lastModified() details.isDirectory = file.isDirectory() } return res } else { return _rootShell.tail(args) } } } @Override def executeShellCommand(args) { handleException { if(log.isDebugEnabled()) { def argsNoStdin = [*:args] def stdin = argsNoStdin.remove('stdin') log.debug("executeShellCommand(${argsNoStdin}${stdin ? ' - stdin ' : ''})") } [id: _commandManager.executeShellCommand(args).id] } } @Override def waitForCommand(args) { handleException { if(log.isDebugEnabled()) log.debug("waitForCommand(${args})") _commandManager.waitForCommand(args) } } @Override def streamCommandResults(args) { handleException { if(log.isDebugEnabled()) log.debug("streamCommandResults(${args})") def res = _commandManager.findCommandExecutionAndStreams(args) if(res == null) throw new NoSuchCommandException(args.id) CommandExecution commandExecution = res.remove('commandExecution') if(commandExecution.startTime > 0) res.startTime = commandExecution.startTime if(commandExecution.isCompleted()) res.completionTime = commandExecution.completionTime return res } } @Override boolean interruptCommand(args) { handleException { if(log.isDebugEnabled()) log.debug("interruptCommand(${args})") _commandManager.interruptCommand(args) } } @Override int getTagsCount() { handleException { return _taggeable.tagsCount } } @Override boolean hasTags() { handleException { return _taggeable.hasTags() } } @Override Set getTags() { handleException { return _taggeable.tags } } @Override boolean hasTag(String tag) { handleException { return _taggeable.hasTag(tag) } } @Override boolean hasAllTags(Collection tags) { handleException { return _taggeable.hasAllTags(tags) } } @Override boolean hasAnyTag(Collection tags) { handleException { return _taggeable.hasAnyTag(tags) } } @Override boolean addTag(String tag) { handleException { log.info "adding tag: ${tag}" return _taggeable.addTag(tag) } } @Override Set addTags(Collection tags) { handleException { log.info "adding tags: ${tags}" return _taggeable.addTags(tags) } } @Override boolean removeTag(String tag) { handleException { log.info "removing tag: ${tag}" return _taggeable.removeTag(tag) } } @Override Set removeTags(Collection tags) { handleException { log.info "removing tags: ${tags}" return _taggeable.removeTags(tags) } } @Override void setTags(Collection tags) { handleException { log.info "setting tags: ${tags}" return _taggeable.setTags(tags) } } private T handleException(Closure closure) { try { return closure() } catch(RuntimeException e) { throw e } catch(TimeoutException e) { // adapting timeout exception... def toex = new TimeOutException(e.message) toex.initCause(e) throw toex } catch (AgentException e) { throw e } catch(Throwable th) { throw new AgentException('unexpected exception', th) } } /** * @return a script previously installed (or null if not found) */ ScriptNode findScript(mountPoint) { return _scriptManager.findScript(mountPoint) } }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy