package io.subutai.core.environment.impl; import java.security.PrivilegedAction; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.Set; import java.util.UUID; import java.util.concurrent.ConcurrentHashMap; import java.util.concurrent.ExecutorService; import java.util.concurrent.Executors; import java.util.concurrent.ScheduledExecutorService; import java.util.concurrent.TimeUnit; import javax.security.auth.Subject; import javax.ws.rs.WebApplicationException; import org.bouncycastle.openpgp.PGPException; import org.bouncycastle.openpgp.PGPPublicKeyRing; import org.bouncycastle.openpgp.PGPSecretKeyRing; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.apache.commons.lang3.StringUtils; import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import io.subutai.bazaar.share.common.BazaaarAdapter; import io.subutai.bazaar.share.common.BazaarEventListener; import io.subutai.bazaar.share.quota.ContainerQuota; import io.subutai.common.command.CommandException; import io.subutai.common.command.RequestBuilder; import io.subutai.common.environment.ContainerDto; import io.subutai.common.environment.ContainerHostNotFoundException; import io.subutai.common.environment.Environment; import io.subutai.common.environment.EnvironmentCreationRef; import io.subutai.common.environment.EnvironmentDto; import io.subutai.common.environment.EnvironmentModificationException; import io.subutai.common.environment.EnvironmentNotFoundException; import io.subutai.common.environment.EnvironmentPeer; import io.subutai.common.environment.EnvironmentStatus; import io.subutai.common.environment.Node; import io.subutai.common.environment.Nodes; import io.subutai.common.environment.Topology; import io.subutai.common.exception.ActionFailedException; import io.subutai.common.host.ContainerHostInfo; import io.subutai.common.host.ContainerHostState; import io.subutai.common.metric.AlertValue; import io.subutai.common.network.NetworkResource; import io.subutai.common.network.ReservedNetworkResources; import io.subutai.common.network.SshTunnel; import io.subutai.common.peer.AlertEvent; import io.subutai.common.peer.AlertHandler; import io.subutai.common.peer.AlertHandlerPriority; import io.subutai.common.peer.AlertListener; import io.subutai.common.peer.ContainerHost; import io.subutai.common.peer.ContainerId; import io.subutai.common.peer.EnvironmentAlertHandler; import io.subutai.common.peer.EnvironmentAlertHandlers; import io.subutai.common.peer.EnvironmentContainerHost; import io.subutai.common.peer.EnvironmentId; import io.subutai.common.peer.HostNotFoundException; import io.subutai.common.peer.LocalPeerEventListener; import io.subutai.common.peer.Peer; import io.subutai.common.peer.PeerException; import io.subutai.common.peer.RemotePeer; import io.subutai.common.protocol.P2pIps; import io.subutai.common.protocol.Template; import io.subutai.common.security.SshEncryptionType; import io.subutai.common.security.SshKey; import io.subutai.common.security.SshKeys; import io.subutai.common.security.crypto.pgp.KeyPair; import io.subutai.common.security.crypto.pgp.PGPKeyUtil; import io.subutai.common.security.objects.SecurityKeyType; import io.subutai.common.security.relation.RelationManager; import io.subutai.common.settings.Common; import io.subutai.common.tracker.TrackerOperation; import io.subutai.common.util.CollectionUtil; import io.subutai.common.util.ExceptionUtil; import io.subutai.common.util.JsonUtil; import io.subutai.common.util.ServiceLocator; import io.subutai.common.util.StringUtil; import io.subutai.common.util.TaskUtil; import io.subutai.core.environment.api.CancellableWorkflow; import io.subutai.core.environment.api.EnvironmentEventListener; import io.subutai.core.environment.api.EnvironmentManager; import io.subutai.core.environment.api.exception.EnvironmentCreationException; import io.subutai.core.environment.api.exception.EnvironmentDestructionException; import io.subutai.core.environment.api.exception.EnvironmentManagerException; import io.subutai.core.environment.impl.adapter.BazaarEnvironment; import io.subutai.core.environment.impl.adapter.EnvironmentAdapter; import io.subutai.core.environment.impl.dao.EnvironmentService; import io.subutai.core.environment.impl.entity.EnvironmentAlertHandlerImpl; import io.subutai.core.environment.impl.entity.EnvironmentContainerImpl; import io.subutai.core.environment.impl.entity.LocalEnvironment; import io.subutai.core.environment.impl.tasks.ContainerDiskUsageCheckTask; import io.subutai.core.environment.impl.tasks.EnvironmentManagerInitTask; import io.subutai.core.environment.impl.tasks.RemoveEnvironmentsTask; import io.subutai.core.environment.impl.tasks.UploadEnvironmentsTask; import io.subutai.core.environment.impl.workflow.creation.EnvironmentCreationWorkflow; import io.subutai.core.environment.impl.workflow.destruction.ContainerDestructionWorkflow; import io.subutai.core.environment.impl.workflow.destruction.EnvironmentDestructionWorkflow; import io.subutai.core.environment.impl.workflow.modification.EnvironmentModifyWorkflow; import io.subutai.core.environment.impl.workflow.modification.HostnameModificationWorkflow; import io.subutai.core.environment.impl.workflow.modification.P2PSecretKeyModificationWorkflow; import io.subutai.core.environment.impl.workflow.modification.SshKeyAdditionWorkflow; import io.subutai.core.environment.impl.workflow.modification.SshKeyRemovalWorkflow; import io.subutai.core.environment.impl.xpeer.RemoteEnvironment; import io.subutai.core.hostregistry.api.HostDisconnectedException; import io.subutai.core.hostregistry.api.HostListener; import io.subutai.core.hostregistry.api.HostRegistry; import io.subutai.core.identity.api.IdentityManager; import io.subutai.core.identity.api.model.Session; import io.subutai.core.identity.api.model.User; import io.subutai.core.identity.api.model.UserDelegate; import io.subutai.core.peer.api.PeerAction; import io.subutai.core.peer.api.PeerActionListener; import io.subutai.core.peer.api.PeerActionResponse; import io.subutai.core.peer.api.PeerManager; import io.subutai.core.security.api.SecurityManager; import io.subutai.core.security.api.crypto.KeyManager; import io.subutai.core.systemmanager.api.SystemManager; import io.subutai.core.template.api.TemplateManager; import io.subutai.core.tracker.api.Tracker; /** * TODO <p> 1) add p2pSecret property to peerConf, set it only after successful p2p secret update on the associated peer * (in P2PSecretKeyResetStep) <p> 2) add secret key TTL property to environment (user should be able to change it - add * to EM API), update background task to consider this TTL (make background task run frequently with short intervals) **/ public class EnvironmentManagerImpl extends HostListener implements EnvironmentManager, PeerActionListener, AlertListener, BazaarEventListener, LocalPeerEventListener { private static final Logger LOG = LoggerFactory.getLogger( EnvironmentManagerImpl.class ); protected static final String MODULE_NAME = "Environment Manager"; private static final long RESET_ENVS_P2P_KEYS_INTERVAL_MIN = 60; private static final long SYNC_ENVS_WITH_BAZAAR_INTERVAL_MIN = 10; private static final String REMOTE_OWNER_NAME = "remote"; private static final String UKNOWN_OWNER_NAME = "unknown"; private static final long CONTAINER_DISK_USAGE_CHECK_INTERVAL_MIN = 6 * 60; // 6 hrs private final IdentityManager identityManager; private final RelationManager relationManager; private final PeerManager peerManager; private final TemplateManager templateManager; private final Tracker tracker; protected Set<EnvironmentEventListener> listeners = Sets.newConcurrentHashSet(); protected ExecutorService executor; protected ExceptionUtil exceptionUtil = new ExceptionUtil(); protected Map<String, AlertHandler> alertHandlers = new ConcurrentHashMap<>(); private SecurityManager securityManager; protected ScheduledExecutorService backgroundTasksExecutorService; protected Map<String, CancellableWorkflow> activeWorkflows = Maps.newConcurrentMap(); private Subject systemUser; private SystemManager systemManager; private EnvironmentAdapter environmentAdapter; private EnvironmentService environmentService; protected JsonUtil jsonUtil = new JsonUtil(); protected PGPKeyUtil pgpKeyUtil = new PGPKeyUtil(); private volatile long lastP2pSecretKeyResetTs = 0L; private volatile long lastEnvSyncTs = 0L; private volatile long lastContainerDiskUsageCheckTs = 0L; public EnvironmentManagerImpl( final TemplateManager templateManager, final PeerManager peerManager, SecurityManager securityManager, final IdentityManager identityManager, final Tracker tracker, final RelationManager relationManager, BazaaarAdapter bazaaarAdapter, final EnvironmentService environmentService, final SystemManager systemManager ) { Preconditions.checkNotNull( templateManager ); Preconditions.checkNotNull( peerManager ); Preconditions.checkNotNull( identityManager ); Preconditions.checkNotNull( relationManager ); Preconditions.checkNotNull( securityManager ); Preconditions.checkNotNull( tracker ); Preconditions.checkNotNull( systemManager ); this.templateManager = templateManager; this.peerManager = peerManager; this.securityManager = securityManager; this.identityManager = identityManager; this.relationManager = relationManager; this.tracker = tracker; this.systemManager = systemManager; //****************************************** Session session = identityManager.loginSystemUser(); if ( session != null ) { systemUser = session.getSubject(); } //****************************************** backgroundTasksExecutorService = getScheduleExecutor(); backgroundTasksExecutorService.scheduleWithFixedDelay( new BackgroundTasksRunner(), 1, 1, TimeUnit.MINUTES ); executor = getCachedExecutor(); environmentAdapter = getEnvironmentAdapter( bazaaarAdapter ); this.environmentService = environmentService; } protected ExecutorService getCachedExecutor() { return Executors.newCachedThreadPool(); } protected ScheduledExecutorService getScheduleExecutor() { return Executors.newSingleThreadScheduledExecutor(); } protected EnvironmentAdapter getEnvironmentAdapter( BazaaarAdapter bazaaarAdapter ) { return new EnvironmentAdapter( this, peerManager, bazaaarAdapter, identityManager ); } public void init() { getCachedExecutor() .execute( new EnvironmentManagerInitTask( peerManager.getLocalPeer(), this, environmentService ) ); } public void dispose() { executor.shutdown(); backgroundTasksExecutorService.shutdown(); for ( CancellableWorkflow cancellableWorkflow : activeWorkflows.values() ) { cancellableWorkflow.cancel(); } } public IdentityManager getIdentityManager() { return identityManager; } public RelationManager getRelationManager() { return relationManager; } @Override public String getName() { return MODULE_NAME; } @Override public PeerActionResponse onPeerAction( final PeerAction peerAction ) { Preconditions.checkNotNull( peerAction ); PeerActionResponse response = PeerActionResponse.Ok(); switch ( peerAction.getType() ) { case UNREGISTER: if ( isPeerInUse( ( String ) peerAction.getData() ) ) { response = PeerActionResponse.Fail( "Peer in use." ); } break; default: LOG.info( "Peer action {}", peerAction.getType() ); break; } return response; } protected boolean isPeerInUse( String peerId ) { for ( LocalEnvironment e : environmentService.getAll() ) { if ( e.getStatus() == EnvironmentStatus.UNDER_MODIFICATION ) { return true; } for ( EnvironmentPeer p : e.getEnvironmentPeers() ) { if ( peerId.equals( p.getPeerId() ) ) { return true; } } } return !peerManager.getLocalPeer().getPeerContainers( peerId ).isEmpty(); } protected Set<Peer> getPeers( final Topology topology ) throws PeerException { final Set<Peer> result = new HashSet<>(); if ( topology != null ) { for ( String peerId : topology.getAllPeers() ) { result.add( peerManager.getPeer( peerId ) ); } } return result; } @Override public Set<Environment> getEnvironments() { Set<Environment> envs = new HashSet<>(); envs.addAll( environmentService.getAll() ); try { Set<BazaarEnvironment> bzrEnvironments = environmentAdapter.getEnvironments( false ); // remove environments that exist onbazaar but don't exist on peer // workaround for https://github.com/subutai-io/base/issues/1464 removeStaleBazaarEnvironments( bzrEnvironments ); envs.addAll( bzrEnvironments ); } catch ( ActionFailedException e ) { //ignore } setTransientFields( envs ); return envs; } public void setTransientFields( Set<Environment> envs ) { for ( Environment env : envs ) { setEnvironmentTransientFields( env ); setContainersTransientFields( env ); } } void setEnvironmentTransientFields( final Environment environment ) { // Using environmentManager for ProxyEnvironment may give side effects. For example, empty container list. if ( !( environment instanceof BazaarEnvironment ) ) { ( ( LocalEnvironment ) environment ).setEnvironmentManager( this ); } } void setContainersTransientFields( final Environment environment ) { Set<EnvironmentContainerHost> containers = environment.getContainerHosts(); for ( ContainerHost containerHost : containers ) { EnvironmentContainerImpl environmentContainer = ( EnvironmentContainerImpl ) containerHost; environmentContainer.setEnvironmentManager( this ); } } @Override public Set<Environment> getEnvironmentsByOwnerId( long userId ) { Set<Environment> envs = new HashSet<>(); for ( Environment env : environmentService.getAll() ) { if ( env.getUserId().equals( userId ) ) { envs.add( env ); } } setTransientFields( envs ); return envs; } Environment createEnvironment( final Topology topology, final boolean async, TrackerOperation operationTracker ) throws EnvironmentCreationException { Preconditions.checkNotNull( topology, "Invalid topology" ); Preconditions.checkArgument( !StringUtils.isBlank( topology.getEnvironmentName() ), "Invalid name" ); Preconditions.checkArgument( !topology.getNodeGroupPlacement().isEmpty(), "Placement is empty" ); Preconditions.checkState( !systemManager.isUpdateInProgress(), "System update in progress" ); //collect participating peers Set<Peer> allPeers; try { allPeers = getPeers( topology ); } catch ( PeerException e ) { operationTracker.addLogFailed( e.getMessage() ); throw new EnvironmentCreationException( e.getMessage() ); } for ( Peer peer : allPeers ) { //check if peers are accessible if ( !peer.isOnline() ) { operationTracker.addLogFailed( String.format( "Peer %s is offline", peer.getName() ) ); throw new EnvironmentCreationException( String.format( "Peer %s is offline", peer.getName() ) ); } try { if ( !peer.canAccommodate( new Nodes( topology.getPeerNodes( peer.getId() ) ) ) ) { operationTracker.addLogFailed( String.format( "Peer %s can not accommodate the requested containers", peer.getName() ) ); throw new EnvironmentCreationException( String.format( "Peer %s can not accommodate the requested containers", peer.getName() ) ); } } catch ( PeerException e ) { operationTracker.addLogFailed( e.getMessage() ); throw new EnvironmentCreationException( e.getMessage() ); } } //create empty environment final LocalEnvironment environment = createEmptyEnvironment( topology ); //launch environment creation workflow final EnvironmentCreationWorkflow environmentCreationWorkflow = getEnvironmentCreationWorkflow( environment, topology, topology.getSshKey(), operationTracker ); registerActiveWorkflow( environment, environmentCreationWorkflow ); //notify environment event listeners environmentCreationWorkflow.onStop( new Runnable() { @Override public void run() { notifyOnEnvironmentCreated( environment ); removeActiveWorkflow( environment.getId() ); } } ); //wait if ( !async ) { environmentCreationWorkflow.join(); if ( environmentCreationWorkflow.isFailed() ) { throw new EnvironmentCreationException( exceptionUtil.getRootCause( environmentCreationWorkflow.getError() ) ); } } //return created environment return environment; } @Override public EnvironmentCreationRef createEnvironment( final Topology topology, final boolean async ) throws EnvironmentCreationException { Preconditions.checkNotNull( topology, "Invalid topology" ); Preconditions.checkArgument( !StringUtils.isBlank( topology.getEnvironmentName() ), "Invalid name" ); Preconditions.checkArgument( !topology.getNodeGroupPlacement().isEmpty(), "Placement is empty" ); if ( !StringUtils.isBlank( topology.getSshKey() ) ) { Preconditions.checkArgument( StringUtil.isValidSshPublicKey( topology.getSshKey() ), "Invalid ssh key" ); } //create operation tracker TrackerOperation operationTracker = tracker.createTrackerOperation( MODULE_NAME, String.format( "Creating environment %s ", topology.getEnvironmentName() ) ); operationTracker.addLog( "Logger initialized" ); return new EnvironmentCreationRef( operationTracker.getId().toString(), createEnvironment( topology, async, operationTracker ).getId() ); } LocalEnvironment createEmptyEnvironment( final Topology topology ) throws EnvironmentCreationException { LocalEnvironment environment = new LocalEnvironment( topology.getEnvironmentName(), topology.getSshKey(), getUserId(), peerManager.getLocalPeer().getId() ); User activeUser = identityManager.getActiveUser(); UserDelegate delegatedUser = identityManager.getUserDelegate( activeUser.getId() ); environment.setRawTopology( jsonUtil.to( topology ) ); environment.setUserId( delegatedUser.getUserId() ); environment.setSshKeyType( topology.getSshKeyType() ); save( environment ); createEnvironmentKeyPair( environment.getEnvironmentId() ); setTransientFields( Sets.<Environment>newHashSet( environment ) ); return environment; } @Override public Set<EnvironmentContainerHost> growEnvironment( final String environmentId, final Topology topology, final boolean async ) throws EnvironmentModificationException, EnvironmentNotFoundException { final LocalEnvironment environment = ( LocalEnvironment ) loadEnvironment( environmentId ); final Set<EnvironmentContainerHost> oldContainers = Sets.newHashSet( environment.getContainerHosts() ); modifyEnvironment( environmentId, topology, null, null, async ); Set<EnvironmentContainerHost> newContainers = Sets.newHashSet(); if ( !async ) { newContainers = Sets.newHashSet( loadEnvironment( environmentId ).getContainerHosts() ); newContainers.removeAll( oldContainers ); } return newContainers; } @Override public EnvironmentCreationRef modifyEnvironment( final String environmentId, final Topology topology, final Set<String> removedContainers, final Map<String, ContainerQuota> changedContainers, final boolean async ) throws EnvironmentModificationException, EnvironmentNotFoundException { Preconditions.checkState( !systemManager.isUpdateInProgress(), "System update in progress" ); boolean hasQuotaModification = !CollectionUtil.isMapEmpty( changedContainers ); boolean hasContainerDestruction = !CollectionUtil.isCollectionEmpty( removedContainers ); boolean hasContainerCreation = topology != null && !CollectionUtil.isCollectionEmpty( topology.getAllPeers() ); Preconditions.checkArgument( hasQuotaModification || hasContainerDestruction || hasContainerCreation, "No environment modification task found" ); Preconditions.checkArgument( !StringUtils.isBlank( environmentId ), "Invalid environment id" ); final LocalEnvironment environment = ( LocalEnvironment ) loadEnvironment( environmentId ); TrackerOperation operationTracker = tracker.createTrackerOperation( MODULE_NAME, String.format( "Modifying environment %s", environment.getName() ) ); operationTracker.addLog( "Logger initialized" ); Set<Peer> allPeers = new HashSet<>(); try { allPeers.addAll( getPeers( topology ) ); allPeers.addAll( environment.getPeers() ); } catch ( PeerException e ) { operationTracker.addLogFailed( e.getMessage() ); throw new EnvironmentModificationException( e.getMessage() ); } for ( Peer peer : allPeers ) { //check if peers are accessible if ( !peer.isOnline() ) { operationTracker.addLogFailed( String.format( "Peer %s is offline", peer.getName() ) ); throw new EnvironmentModificationException( String.format( "Peer %s is offline", peer.getName() ) ); } Set<Node> newNodes = topology == null ? Sets.<Node>newHashSet() : topology.getPeerNodes( peer.getId() ); Map<String, ContainerQuota> changedQuotas = getPeerChangedContainers( peer.getId(), changedContainers, environment ); //check if peer can accommodate the requested nodes if ( ( hasContainerCreation && !newNodes.isEmpty() ) || ( hasQuotaModification && !changedQuotas .isEmpty() ) ) { try { if ( !peer.canAccommodate( new Nodes( newNodes, removedContainers, changedQuotas ) ) ) { operationTracker.addLogFailed( String.format( "Peer %s can not accommodate the requested containers", peer.getName() ) ); throw new EnvironmentModificationException( String.format( "Peer %s can not accommodate the requested containers", peer.getName() ) ); } } catch ( PeerException e ) { operationTracker.addLogFailed( e.getMessage() ); throw new EnvironmentModificationException( e.getMessage() ); } } } if ( environment.getStatus() == EnvironmentStatus.UNDER_MODIFICATION || environment.getStatus() == EnvironmentStatus.CANCELLED ) { operationTracker.addLogFailed( String.format( "Environment status is %s", environment.getStatus() ) ); throw new EnvironmentModificationException( String.format( "Environment status is %s", environment.getStatus() ) ); } final Set<EnvironmentContainerHost> oldContainers = Sets.newHashSet( environment.getContainerHosts() ); //launch environment growing workflow final EnvironmentModifyWorkflow environmentModifyWorkflow = getEnvironmentModifyingWorkflow( environment, topology, operationTracker, removedContainers, changedContainers ); registerActiveWorkflow( environment, environmentModifyWorkflow ); //notify environment event listeners environmentModifyWorkflow.onStop( new Runnable() { @Override public void run() { try { Set<EnvironmentContainerHost> newContainers = Sets.newHashSet( environment.getContainerHosts() ); newContainers.removeAll( oldContainers ); notifyOnEnvironmentGrown( loadEnvironment( environment.getId() ), newContainers ); removeActiveWorkflow( environment.getId() ); } catch ( EnvironmentNotFoundException e ) { LOG.error( "Error notifying environment event listeners", e ); } } } ); //wait if ( !async ) { environmentModifyWorkflow.join(); if ( environmentModifyWorkflow.isFailed() ) { throw new EnvironmentModificationException( exceptionUtil.getRootCause( environmentModifyWorkflow.getError() ) ); } else { Set<EnvironmentContainerHost> newContainers = Sets.newHashSet( loadEnvironment( environment.getId() ).getContainerHosts() ); newContainers.removeAll( oldContainers ); } } return new EnvironmentCreationRef( operationTracker.getId().toString(), environmentId ); } private Map<String, ContainerQuota> getPeerRemovedQuotas( final String peerId, final List<String> removedNodes, final LocalEnvironment environment ) throws EnvironmentModificationException { if ( CollectionUtil.isCollectionEmpty( removedNodes ) ) { return Maps.newHashMap(); } try { Map<String, ContainerQuota> peerRemovedNodes = Maps.newHashMap(); for ( String containerId : removedNodes ) { final ContainerHost containerHost = environment.getContainerHostById( containerId ); if ( Objects.equals( containerHost.getPeerId(), peerId ) ) { peerRemovedNodes.put( containerHost.getResourceHostId().getId(), containerHost.getQuota() ); } } return peerRemovedNodes; } catch ( Exception e ) { throw new EnvironmentModificationException( e ); } } private Map<String, ContainerQuota> getPeerChangedContainers( final String peerId, final Map<String, ContainerQuota> allChangedContainers, final LocalEnvironment environment ) throws EnvironmentModificationException { if ( allChangedContainers == null ) { return Maps.newHashMap(); } try { Map<String, ContainerQuota> peerChangedContainers = Maps.newHashMap(); for ( Map.Entry<String, ContainerQuota> entry : allChangedContainers.entrySet() ) { String containerId = entry.getKey(); EnvironmentContainerHost containerHost = environment.getContainerHostById( containerId ); if ( Objects.equals( containerHost.getPeerId(), peerId ) ) { peerChangedContainers.put( containerId, entry.getValue() ); } } return peerChangedContainers; } catch ( Exception e ) { throw new EnvironmentModificationException( e ); } } @Override public void addSshKey( final String environmentId, final String sshKey, final boolean async ) throws EnvironmentNotFoundException, EnvironmentModificationException { Preconditions.checkArgument( !StringUtils.isBlank( environmentId ), "Invalid environment id" ); Preconditions.checkArgument( StringUtil.isValidSshPublicKey( sshKey ), "Invalid ssh key" ); Preconditions.checkState( !systemManager.isUpdateInProgress(), "System update in progress" ); final LocalEnvironment environment = ( LocalEnvironment ) loadEnvironment( environmentId ); TrackerOperation operationTracker = tracker.createTrackerOperation( MODULE_NAME, String.format( "Adding ssh key %s to environment %s ", sshKey, environment.getName() ) ); if ( environment.getStatus() == EnvironmentStatus.UNDER_MODIFICATION || environment.getStatus() == EnvironmentStatus.CANCELLED ) { operationTracker.addLogFailed( String.format( "Environment status is %s", environment.getStatus() ) ); throw new EnvironmentModificationException( String.format( "Environment status is %s", environment.getStatus() ) ); } final SshKeyAdditionWorkflow sshKeyAdditionWorkflow = getSshKeyAdditionWorkflow( environment, sshKey.trim(), operationTracker ); registerActiveWorkflow( environment, sshKeyAdditionWorkflow ); sshKeyAdditionWorkflow.onStop( new Runnable() { @Override public void run() { removeActiveWorkflow( environment.getId() ); } } ); //wait if ( !async ) { sshKeyAdditionWorkflow.join(); if ( sshKeyAdditionWorkflow.isFailed() ) { throw new EnvironmentModificationException( exceptionUtil.getRootCause( sshKeyAdditionWorkflow.getError() ) ); } } environmentAdapter.addSshKey( environmentId, sshKey ); } @Override public void removeSshKey( final String environmentId, final String sshKey, final boolean async ) throws EnvironmentNotFoundException, EnvironmentModificationException { Preconditions.checkArgument( !StringUtils.isBlank( environmentId ), "Invalid environment id" ); Preconditions.checkArgument( !StringUtils.isBlank( sshKey ), "Invalid ssh key" ); Preconditions.checkState( !systemManager.isUpdateInProgress(), "System update in progress" ); final LocalEnvironment environment = ( LocalEnvironment ) loadEnvironment( environmentId ); TrackerOperation operationTracker = tracker.createTrackerOperation( MODULE_NAME, String.format( "Removing ssh key %s from environment %s ", sshKey, environment.getName() ) ); if ( environment.getStatus() == EnvironmentStatus.UNDER_MODIFICATION || environment.getStatus() == EnvironmentStatus.CANCELLED ) { operationTracker.addLogFailed( String.format( "Environment status is %s", environment.getStatus() ) ); throw new EnvironmentModificationException( String.format( "Environment status is %s", environment.getStatus() ) ); } final SshKeyRemovalWorkflow sshKeyRemovalWorkflow = getSshKeyRemovalWorkflow( environment, sshKey.trim(), operationTracker ); registerActiveWorkflow( environment, sshKeyRemovalWorkflow ); sshKeyRemovalWorkflow.onStop( new Runnable() { @Override public void run() { removeActiveWorkflow( environment.getId() ); } } ); //wait if ( !async ) { sshKeyRemovalWorkflow.join(); if ( sshKeyRemovalWorkflow.isFailed() ) { throw new EnvironmentModificationException( exceptionUtil.getRootCause( sshKeyRemovalWorkflow.getError() ) ); } } environmentAdapter.removeSshKey( environmentId, sshKey ); } @Override public SshKeys getSshKeys( final String environmentId, final SshEncryptionType encType ) { SshKeys sshKeys = new SshKeys(); try { Environment environment = loadEnvironment( environmentId ); for ( Peer peer : environment.getPeers() ) { SshKeys keys = peer.getSshKeys( environment.getEnvironmentId(), encType ); sshKeys.addKeys( keys.getKeys() ); } } catch ( Exception e ) { LOG.error( e.getMessage(), e ); } return sshKeys; } @Override public SshKeys createSshKey( final String environmentId, final String hostname, final SshEncryptionType encType ) { SshKeys sshKeys = new SshKeys(); try { Environment environment = loadEnvironment( environmentId ); ContainerHost host = environment.getContainerHostByHostname( hostname ); SshKey sshKey = host.getPeer().createSshKey( environment.getEnvironmentId(), host.getContainerId(), encType ); sshKeys.addKey( sshKey ); } catch ( Exception e ) { LOG.error( e.getMessage(), e ); throw new WebApplicationException( e.getMessage() ); } return sshKeys; } @Override public void resetP2PSecretKey( final String environmentId, final String newP2pSecretKey, final long p2pSecretKeyTtlSec, final boolean async ) throws EnvironmentNotFoundException, EnvironmentModificationException { Preconditions.checkArgument( !StringUtils.isBlank( environmentId ), "Invalid environment id" ); Preconditions.checkArgument( !StringUtils.isBlank( newP2pSecretKey ), "Invalid p2p secret key" ); Preconditions.checkArgument( p2pSecretKeyTtlSec > 0, "Invalid p2p secret key time-to-live" ); Preconditions.checkState( !systemManager.isUpdateInProgress(), "System update in progress" ); final LocalEnvironment environment = ( LocalEnvironment ) loadEnvironment( environmentId ); TrackerOperation operationTracker = tracker.createTrackerOperation( MODULE_NAME, String.format( "Resetting p2p secret key for environment %s ", environment.getName() ) ); if ( environment.getStatus() == EnvironmentStatus.UNDER_MODIFICATION || environment.getStatus() == EnvironmentStatus.CANCELLED ) { operationTracker.addLogFailed( String.format( "Environment status is %s", environment.getStatus() ) ); throw new EnvironmentModificationException( String.format( "Environment status is %s", environment.getStatus() ) ); } final P2PSecretKeyModificationWorkflow p2PSecretKeyModificationWorkflow = getP2PSecretKeyModificationWorkflow( environment, newP2pSecretKey, p2pSecretKeyTtlSec, operationTracker ); registerActiveWorkflow( environment, p2PSecretKeyModificationWorkflow ); p2PSecretKeyModificationWorkflow.onStop( new Runnable() { @Override public void run() { removeActiveWorkflow( environment.getId() ); } } ); //wait if ( !async ) { p2PSecretKeyModificationWorkflow.join(); if ( p2PSecretKeyModificationWorkflow.isFailed() ) { throw new EnvironmentModificationException( exceptionUtil.getRootCause( p2PSecretKeyModificationWorkflow.getError() ) ); } } } @Override public void destroyEnvironment( final String environmentId, final boolean async ) throws EnvironmentDestructionException, EnvironmentNotFoundException { Preconditions.checkArgument( !StringUtils.isBlank( environmentId ), "Invalid environment id" ); Preconditions.checkState( !systemManager.isUpdateInProgress(), "System update in progress" ); LocalEnvironment environment; try { environment = ( LocalEnvironment ) loadEnvironment( environmentId ); } catch ( EnvironmentNotFoundException e ) { // try to get remote environment environment = findRemoteEnvironment( environmentId ); if ( environment == null ) { throw e; } } // If environment frombazaar, send destroy request tobazaar if ( environment instanceof BazaarEnvironment ) { environmentAdapter.removeEnvironment( environment ); notifyOnEnvironmentDestroyed( environmentId ); return; } else if ( environment instanceof RemoteEnvironment ) { try { peerManager.getLocalPeer().cleanupEnvironment( environment.getEnvironmentId() ); } catch ( PeerException e ) { throw new EnvironmentDestructionException( e ); } // notify initiator peer to exclude this peer from the environment RemotePeer initiatorPeer = peerManager.findPeer( ( ( RemoteEnvironment ) environment ).getInitiatorPeerId() ); if ( initiatorPeer != null ) { try { initiatorPeer.excludePeerFromEnvironment( environment.getId(), peerManager.getLocalPeer().getId() ); } catch ( Exception e ) { LOG.error( "Error excluding local peer from remote environment: {}", e.getMessage() ); } } notifyOnEnvironmentDestroyed( environmentId ); return; } TrackerOperation operationTracker = tracker.createTrackerOperation( MODULE_NAME, String.format( "Destroying environment %s", environment.getName() ) ); if ( environment.getStatus() == EnvironmentStatus.UNDER_MODIFICATION ) { operationTracker.addLogFailed( String.format( "Environment status is %s", environment.getStatus() ) ); throw new EnvironmentDestructionException( String.format( "Environment status is %s", environment.getStatus() ) ); } final EnvironmentDestructionWorkflow environmentDestructionWorkflow = getEnvironmentDestructionWorkflow( environment, operationTracker ); registerActiveWorkflow( environment, environmentDestructionWorkflow ); environmentDestructionWorkflow.onStop( new Runnable() { @Override public void run() { try { loadEnvironment( environmentId ); } catch ( EnvironmentNotFoundException e ) { notifyOnEnvironmentDestroyed( environmentId ); } removeActiveWorkflow( environmentId ); } } ); //wait if ( !async ) { environmentDestructionWorkflow.join(); if ( environmentDestructionWorkflow.isFailed() ) { throw new EnvironmentDestructionException( exceptionUtil.getRootCause( environmentDestructionWorkflow.getError() ) ); } } } @Override public void destroyContainer( final String environmentId, final String containerId, final boolean async ) throws EnvironmentModificationException, EnvironmentNotFoundException { Preconditions.checkArgument( !StringUtils.isBlank( environmentId ), "Invalid environment id" ); Preconditions.checkArgument( !StringUtils.isBlank( containerId ), "Invalid container id" ); Preconditions.checkState( !systemManager.isUpdateInProgress(), "System update in progress" ); final LocalEnvironment environment = ( LocalEnvironment ) loadEnvironment( environmentId ); if ( environment instanceof BazaarEnvironment ) { try { environmentAdapter.destroyContainer( ( BazaarEnvironment ) environment, containerId ); } catch ( IllegalStateException e ) { throw new EnvironmentModificationException( e ); } return; } if ( environment.getStatus() == EnvironmentStatus.UNDER_MODIFICATION ) { throw new EnvironmentModificationException( String.format( "Environment status is %s", environment.getStatus() ) ); } ContainerHost environmentContainer; try { environmentContainer = environment.getContainerHostById( containerId ); } catch ( ContainerHostNotFoundException e ) { throw new EnvironmentModificationException( e ); } TrackerOperation operationTracker = tracker.createTrackerOperation( MODULE_NAME, String.format( "Destroying container %s", environmentContainer.getHostname() ) ); final ContainerDestructionWorkflow containerDestructionWorkflow = getContainerDestructionWorkflow( environment, environmentContainer, operationTracker ); registerActiveWorkflow( environment, containerDestructionWorkflow ); containerDestructionWorkflow.onStop( new Runnable() { @Override public void run() { removeActiveWorkflow( environment.getId() ); } } ); //wait if ( !async ) { containerDestructionWorkflow.join(); if ( containerDestructionWorkflow.isFailed() ) { throw new EnvironmentModificationException( exceptionUtil.getRootCause( containerDestructionWorkflow.getError() ) ); } } } @Override public void changeContainerHostname( final ContainerId containerId, final String newHostname, final boolean async ) throws EnvironmentModificationException, EnvironmentNotFoundException, ContainerHostNotFoundException { Preconditions.checkNotNull( containerId, "Invalid container id" ); Preconditions.checkArgument( !StringUtils.isBlank( newHostname ), "Invalid hostname" ); Preconditions.checkState( !systemManager.isUpdateInProgress(), "System update in progress" ); final LocalEnvironment environment = ( LocalEnvironment ) loadEnvironment( containerId.getEnvironmentId().getId() ); //check that container exists in the environment environment.getContainerHostById( containerId.getId() ); TrackerOperation operationTracker = tracker.createTrackerOperation( MODULE_NAME, String.format( "Changing container hostname(s) in environment %s", environment.getName() ) ); final HostnameModificationWorkflow hostnameModificationWorkflow = getHostnameModificationWorkflow( environment, containerId, newHostname, operationTracker ); registerActiveWorkflow( environment, hostnameModificationWorkflow ); hostnameModificationWorkflow.onStop( new Runnable() { @Override public void run() { removeActiveWorkflow( environment.getId() ); } } ); //wait if ( !async ) { hostnameModificationWorkflow.join(); if ( hostnameModificationWorkflow.isFailed() ) { throw new EnvironmentModificationException( exceptionUtil.getRootCause( hostnameModificationWorkflow.getError() ) ); } } } @Override public void createTemplate( final String environmentId, final String containerId, final String templateName, final String version, final boolean privateTemplate ) throws PeerException, EnvironmentNotFoundException { Preconditions.checkArgument( !StringUtils.isBlank( environmentId ), "Invalid environment id" ); Preconditions.checkArgument( !StringUtils.isBlank( containerId ), "Invalid container id" ); Preconditions.checkArgument( !StringUtils.isBlank( templateName ), "Invalid template name" ); Preconditions.checkArgument( !StringUtils.isBlank( version ), "Invalid version" ); Preconditions.checkArgument( version.matches( "^\\d+\\.\\d+\\.\\d+$" ), "Version must be in X.X.X format" ); String cdnToken = identityManager.getActiveSession().getCdnToken(); Preconditions.checkNotNull( cdnToken, "Cdn token is missing or expired" ); final LocalEnvironment environment = ( LocalEnvironment ) loadEnvironment( environmentId ); //check that container exists in the environment EnvironmentContainerHost containerHost = environment.getContainerHostById( containerId ); Preconditions.checkArgument( containerHost.isLocal(), "Container must be local" ); String owner = templateManager.getOwner( cdnToken ); Preconditions.checkNotNull( owner, "Owner not found" ); List<Template> ownerTemplates = templateManager.getTemplatesByOwner( owner ); for ( Template template : ownerTemplates ) { if ( templateName.equalsIgnoreCase( template.getName() ) && version .equalsIgnoreCase( template.getVersion() ) ) { throw new IllegalStateException( String.format( "Template with name %s and version %s already exists in your repository", templateName, version ) ); } } peerManager.getLocalPeer() .exportTemplate( containerHost.getContainerId(), templateName, version, privateTemplate, cdnToken ); LOG.info( "Template exported" ); } protected void registerActiveWorkflow( Environment environment, CancellableWorkflow newWorkflow ) { Preconditions.checkNotNull( environment ); Preconditions.checkNotNull( newWorkflow ); CancellableWorkflow checkWorkflow = activeWorkflows.get( environment.getId() ); if ( checkWorkflow != null ) { throw new IllegalStateException( String.format( "There is already an active workflow %s for environment %s", checkWorkflow.getClass().getSimpleName(), environment.getName() ) ); } activeWorkflows.put( environment.getId(), newWorkflow ); } protected void removeActiveWorkflow( String environmentId ) { Preconditions.checkArgument( !StringUtils.isBlank( environmentId ) ); activeWorkflows.remove( environmentId ); } @Override public void cancelEnvironmentWorkflow( final String environmentId ) throws EnvironmentManagerException { try { CancellableWorkflow activeWorkflow = activeWorkflows.get( environmentId ); if ( activeWorkflow != null ) { activeWorkflow.cancel(); removeActiveWorkflow( environmentId ); } else { LocalEnvironment environment = environmentService.find( environmentId ); if ( environment != null ) { environment.setStatus( EnvironmentStatus.CANCELLED ); update( environment ); } } } catch ( Exception e ) { LOG.error( "Error cancelling environment workflow: {}", e.getMessage() ); throw new EnvironmentManagerException( String.format( "Error cancelling environment workflow %s", e.getMessage() ) ); } } @Override public Map<String, CancellableWorkflow> getActiveWorkflows() { return Collections.unmodifiableMap( activeWorkflows ); } @Override public Environment loadEnvironment( final String environmentId ) throws EnvironmentNotFoundException { Preconditions.checkNotNull( environmentId, "Invalid environment id" ); // First get frombazaar LocalEnvironment environment = environmentAdapter.get( environmentId ); if ( environment != null ) { return environment; } // try to get local environment environment = environmentService.find( environmentId ); if ( environment != null ) { setTransientFields( Sets.<Environment>newHashSet( environment ) ); return environment; } throw new EnvironmentNotFoundException(); } LocalEnvironment findRemoteEnvironment( String environmentId ) { try { NetworkResource networkResource = peerManager.getLocalPeer().getReservedNetworkResources().findByEnvironmentId( environmentId ); if ( networkResource != null && !peerManager.getLocalPeer().getId() .equals( networkResource.getInitiatorPeerId() ) ) { RemotePeer initiatorPeer = peerManager.findPeer( networkResource.getInitiatorPeerId() ); return new RemoteEnvironment( networkResource, String.format( "Of %s", initiatorPeer == null ? networkResource.getInitiatorPeerId() : initiatorPeer.getName() ), peerManager.getLocalPeer().findContainersByEnvironmentId( environmentId ) ); } } catch ( PeerException e ) { LOG.error( "Error finding remote environment: {}", e.getMessage() ); } return null; } //************ utility methods @Override public SshTunnel setupSshTunnelForContainer( final String containerHostId, final String environmentId ) throws EnvironmentModificationException, EnvironmentNotFoundException, ContainerHostNotFoundException { Preconditions.checkArgument( !StringUtils.isBlank( containerHostId ), "Invalid container id" ); Preconditions.checkArgument( !StringUtils.isBlank( environmentId ), "Invalid environment id" ); final LocalEnvironment environment = ( LocalEnvironment ) loadEnvironment( environmentId ); EnvironmentContainerHost environmentContainer = environment.getContainerHostById( containerHostId ); TrackerOperation operationTracker = tracker.createTrackerOperation( MODULE_NAME, String.format( "Setting up ssh tunnel for container %s ", environmentContainer.getHostname() ) ); try { SshTunnel sshTunnel = peerManager.getLocalPeer().setupSshTunnelForContainer( environmentContainer.getIp(), Common.CONTAINER_SSH_TIMEOUT_SEC ); operationTracker.addLogDone( String.format( "Ssh for container %s is ready on tunnel %s", environmentContainer.getHostname(), sshTunnel ) ); return sshTunnel; } catch ( Exception e ) { operationTracker.addLogFailed( String.format( "Error setting up ssh for container %s: %s", environmentContainer.getHostname(), e.getMessage() ) ); throw new EnvironmentModificationException( e ); } } PGPSecretKeyRing createEnvironmentKeyPair( EnvironmentId envId ) throws EnvironmentCreationException { KeyManager keyManager = securityManager.getKeyManager(); String pairId = envId.getId(); try { KeyPair keyPair = keyManager.generateKeyPair( pairId, false ); //******Create PEK ***************************************************************** PGPSecretKeyRing secRing = pgpKeyUtil.getSecretKeyRing( keyPair.getSecKeyring() ); PGPPublicKeyRing pubRing = pgpKeyUtil.getPublicKeyRing( keyPair.getPubKeyring() ); //***************Save Keys ********************************************************* keyManager.saveSecretKeyRing( pairId, SecurityKeyType.ENVIRONMENT_KEY.getId(), secRing ); keyManager.savePublicKeyRing( pairId, SecurityKeyType.ENVIRONMENT_KEY.getId(), pubRing ); return secRing; } catch ( PGPException ex ) { throw new EnvironmentCreationException( ex ); } } //-- workflow factories start protected P2PSecretKeyModificationWorkflow getP2PSecretKeyModificationWorkflow( final LocalEnvironment environment, final String p2pSecretKey, final long p2pSecretKeyTtlSec, final TrackerOperation operationTracker ) { return new P2PSecretKeyModificationWorkflow( environment, p2pSecretKey, p2pSecretKeyTtlSec, operationTracker, this ); } protected SshKeyAdditionWorkflow getSshKeyAdditionWorkflow( final LocalEnvironment environment, final String sshKey, final TrackerOperation operationTracker ) { return new SshKeyAdditionWorkflow( environment, sshKey, operationTracker, this ); } protected SshKeyRemovalWorkflow getSshKeyRemovalWorkflow( final LocalEnvironment environment, final String sshKey, final TrackerOperation operationTracker ) { return new SshKeyRemovalWorkflow( environment, sshKey, operationTracker, this ); } protected ContainerDestructionWorkflow getContainerDestructionWorkflow( final LocalEnvironment environment, final ContainerHost containerHost, final TrackerOperation operationTracker ) { return new ContainerDestructionWorkflow( this, environment, containerHost, operationTracker ); } protected EnvironmentCreationWorkflow getEnvironmentCreationWorkflow( final LocalEnvironment environment, final Topology topology, final String sshKey, final TrackerOperation operationTracker ) { return new EnvironmentCreationWorkflow( Common.DEFAULT_DOMAIN_NAME, identityManager, this, peerManager, securityManager, environment, topology, sshKey, operationTracker ); } protected EnvironmentModifyWorkflow getEnvironmentModifyingWorkflow( final LocalEnvironment environment, final Topology topology, final TrackerOperation operationTracker, final Set<String> removedContainers, final Map<String, ContainerQuota> changedContainers ) { return new EnvironmentModifyWorkflow( Common.DEFAULT_DOMAIN_NAME, identityManager, peerManager, securityManager, environment, topology, removedContainers, changedContainers, operationTracker, this ); } protected EnvironmentDestructionWorkflow getEnvironmentDestructionWorkflow( final LocalEnvironment environment, final TrackerOperation operationTracker ) { return new EnvironmentDestructionWorkflow( this, environment, operationTracker ); } protected HostnameModificationWorkflow getHostnameModificationWorkflow( final LocalEnvironment environment, final ContainerId containerId, final String newHostname, final TrackerOperation operationTracker ) { return new HostnameModificationWorkflow( environment, containerId, newHostname, operationTracker, this ); } //-- workflow factories end public void registerListener( final EnvironmentEventListener listener ) { if ( listener != null ) { listeners.add( listener ); } } public void unregisterListener( final EnvironmentEventListener listener ) { if ( listener != null ) { listeners.remove( listener ); } } public void notifyOnEnvironmentCreated( final Environment environment ) { for ( final EnvironmentEventListener listener : listeners ) { executor.submit( new Runnable() { @Override public void run() { listener.onEnvironmentCreated( environment ); } } ); } } public void notifyOnEnvironmentGrown( final Environment environment, final Set<EnvironmentContainerHost> containers ) { if ( !containers.isEmpty() ) { for ( final EnvironmentEventListener listener : listeners ) { executor.submit( new Runnable() { @Override public void run() { listener.onEnvironmentGrown( environment, containers ); } } ); } } } @Override public void notifyOnContainerDestroyed( final Environment environment, final String containerId ) { for ( final EnvironmentEventListener listener : listeners ) { executor.submit( new Runnable() { @Override public void run() { listener.onContainerDestroyed( environment, containerId ); } } ); } } @Override public void notifyOnEnvironmentDestroyed( final String environmentId ) { for ( final EnvironmentEventListener listener : listeners ) { executor.submit( new Runnable() { @Override public void run() { listener.onEnvironmentDestroyed( environmentId ); } } ); } } public void notifyOnContainerStarted( final Environment environment, final String containerId ) { for ( final EnvironmentEventListener listener : listeners ) { executor.submit( new Runnable() { @Override public void run() { listener.onContainerStarted( environment, containerId ); } } ); } } public void notifyOnContainerStopped( final Environment environment, final String containerId ) { for ( final EnvironmentEventListener listener : listeners ) { executor.submit( new Runnable() { @Override public void run() { listener.onContainerStopped( environment, containerId ); } } ); } } @Override public void onContainerDestroyed( final ContainerHostInfo containerInfo ) { try { ContainerHost containerHost = peerManager.getLocalPeer().getContainerHostById( containerInfo.getId() ); onContainerDestroyed( containerHost ); } catch ( HostNotFoundException ignore ) { //no-op } } protected Long getUserId() { return identityManager.getActiveUser().getId(); } public Peer resolvePeer( final String peerId ) throws PeerException { return peerManager.getPeer( peerId ); } public void save( final LocalEnvironment environment ) { environmentService.persist( environment ); setTransientFields( Sets.<Environment>newHashSet( environment ) ); } public synchronized LocalEnvironment update( LocalEnvironment environment ) { if ( environment instanceof BazaarEnvironment ) { // Environment frombazaar return environment; } environment = environmentService.merge( environment ); setTransientFields( Sets.<Environment>newHashSet( environment ) ); boolean uploaded = environmentAdapter.uploadEnvironment( environment ); if ( !uploaded ) { environment.markAsNotUploaded(); environment = environmentService.merge( environment ); setTransientFields( Sets.<Environment>newHashSet( environment ) ); } return environment; } public void remove( final LocalEnvironment environment ) { if ( !environmentAdapter.isRegisteredWithBazaar() || environmentAdapter.removeEnvironment( environment ) ) { environmentService.remove( environment.getId() ); } else { environment.markAsDeleted(); environmentService.merge( environment ); } } public synchronized EnvironmentContainerImpl update( final EnvironmentContainerImpl container ) { Environment environment = container.getEnvironment(); EnvironmentContainerImpl envContainer = environmentService.mergeContainer( container ); envContainer.setEnvironmentManager( this ); //update cache ( ( LocalEnvironment ) environment ).removeContainer( envContainer ); ( ( LocalEnvironment ) environment ).addContainers( Sets.newHashSet( envContainer ) ); return envContainer; } @Override public void addAlertHandler( final AlertHandler alertHandler ) { if ( alertHandler != null && alertHandler.getId() != null ) { this.alertHandlers.put( alertHandler.getId(), alertHandler ); } else { LOG.warn( "Alert handler rejected: " + alertHandler ); } } @Override public void removeAlertHandler( final AlertHandler alertHandler ) { if ( alertHandler != null ) { this.alertHandlers.remove( alertHandler.getId() ); } } @Override public Collection<AlertHandler> getRegisteredAlertHandlers() { return new ArrayList<>( alertHandlers.values() ); } @Override public String getId() { return "ENVIRONMENT_MANAGER"; } @Override public void onAlert( final AlertEvent alertEvent ) { try { EnvironmentAlertHandlers handlers = getEnvironmentAlertHandlers( new EnvironmentId( alertEvent.getEnvironmentId() ) ); handleAlertPack( alertEvent, handlers ); } catch ( Exception e ) { LOG.error( "Error in handling alert package.", e ); } } @Override public EnvironmentAlertHandlers getEnvironmentAlertHandlers( final EnvironmentId environmentId ) throws EnvironmentNotFoundException { Environment environment = loadEnvironment( environmentId.getId() ); Set<EnvironmentAlertHandler> handlerList = environment.getAlertHandlers(); EnvironmentAlertHandlers handlers = new EnvironmentAlertHandlersImpl( environment.getEnvironmentId() ); for ( EnvironmentAlertHandler environmentAlertHandler : handlerList ) { handlers.add( environmentAlertHandler, alertHandlers.get( environmentAlertHandler.getAlertHandlerId() ) ); } return handlers; } protected void handleAlertPack( final AlertEvent alertEvent, EnvironmentAlertHandlers handlers ) { for ( final EnvironmentAlertHandler handlerId : handlers.getAllHandlers().keySet() ) { try { AlertHandler handler = handlers.getHandler( handlerId ); if ( handler == null ) { alertEvent.addLog( String.format( "Alert Handler not found: %s. Skipped.", handlerId ) ); continue; } AlertValue alertValue = alertEvent.getResource().getAlertValue( handler.getSupportedAlertValue() ); if ( alertValue != null && alertEvent.getEnvironmentId() != null ) { final Environment environment = loadEnvironment( alertEvent.getEnvironmentId() ); alertEvent.addLog( String.format( "Invoking pre-processor of '%s:%s'.", handlerId.getAlertHandlerId(), handlerId.getAlertHandlerPriority() ) ); handler.preProcess( environment, alertValue ); alertEvent.addLog( String.format( "Pre-processor of '%s:%s' finished.", handlerId.getAlertHandlerId(), handlerId.getAlertHandlerPriority() ) ); alertEvent.addLog( String.format( "Invoking main processor of '%s:%s'.", handlerId.getAlertHandlerId(), handlerId.getAlertHandlerPriority() ) ); handler.process( environment, alertValue ); alertEvent.addLog( String.format( "Main processor of '%s:%s' finished.", handlerId.getAlertHandlerId(), handlerId.getAlertHandlerPriority() ) ); alertEvent.addLog( String.format( "Invoking post-processor of '%s:%s'.", handlerId.getAlertHandlerId(), handlerId.getAlertHandlerPriority() ) ); handler.postProcess( environment, alertValue ); alertEvent.addLog( String.format( "Pre-processor of '%s:%s' finished.", handlerId.getAlertHandlerId(), handlerId.getAlertHandlerPriority() ) ); } } catch ( Exception e ) { alertEvent.addLog( e.getMessage() ); } } } @Override public void startMonitoring( final String handlerId, final AlertHandlerPriority handlerPriority, final String environmentId ) throws EnvironmentManagerException { Preconditions.checkArgument( !StringUtils.isBlank( handlerId ), "Invalid alert handler id." ); Preconditions.checkNotNull( handlerPriority, "Invalid alert priority." ); AlertHandler alertHandler = alertHandlers.get( handlerId ); if ( alertHandler == null ) { throw new EnvironmentManagerException( "Alert handler not found." ); } try { LocalEnvironment environment = ( LocalEnvironment ) loadEnvironment( environmentId ); environment.addAlertHandler( new EnvironmentAlertHandlerImpl( handlerId, handlerPriority ) ); update( environment ); } catch ( Exception e ) { LOG.error( "Error on start monitoring", e ); throw new EnvironmentManagerException( e.getMessage(), e ); } } @Override public void stopMonitoring( final String handlerId, final AlertHandlerPriority handlerPriority, final String environmentId ) throws EnvironmentManagerException { Preconditions.checkArgument( !StringUtils.isBlank( handlerId ), "Invalid alert handler id." ); Preconditions.checkNotNull( handlerPriority, "Invalid alert priority." ); //remove subscription from database try { LocalEnvironment environment = environmentService.find( environmentId ); environment.removeAlertHandler( new EnvironmentAlertHandlerImpl( handlerId, handlerPriority ) ); update( environment ); } catch ( Exception e ) { LOG.error( "Error on E monitoring", e ); throw new EnvironmentManagerException( e.getMessage(), e ); } } @Override public void addSshKeyToEnvironmentEntity( final String environmentId, final String sshKey ) throws EnvironmentNotFoundException { Preconditions.checkArgument( !StringUtils.isBlank( environmentId ), "Invalid environment id" ); Preconditions.checkArgument( !StringUtils.isBlank( sshKey ), "Invalid ssh key" ); LocalEnvironment environment = ( LocalEnvironment ) loadEnvironment( environmentId ); environment.addSshKey( sshKey ); update( environment ); } @Override public void excludePeerFromEnvironment( final String environmentId, final String peerId ) throws EnvironmentNotFoundException { LocalEnvironment environment = ( LocalEnvironment ) loadEnvironment( environmentId ); Set<EnvironmentContainerHost> peerContainers = environment.getContainerHostsByPeerId( peerId ); EnvironmentPeer environmentPeer = environment.getEnvironmentPeer( peerId ); destroyTunnelToPeer( environmentPeer, environment ); environment.excludePeerFromEnvironment( peerId ); if ( environment.getEnvironmentPeers().isEmpty() ) { remove( environment ); notifyOnEnvironmentDestroyed( environmentId ); relationManager.removeRelation( environment ); cleanupEnvironment( environment.getEnvironmentId() ); } else { update( environment ); for ( EnvironmentContainerHost containerHost : peerContainers ) { notifyOnContainerDestroyed( environment, containerHost.getId() ); } } } @Override public void excludeContainerFromEnvironment( final String environmentId, final String containerId ) throws EnvironmentNotFoundException, ContainerHostNotFoundException { LocalEnvironment environment = ( LocalEnvironment ) loadEnvironment( environmentId ); EnvironmentContainerHost containerHost = environment.getContainerHostById( containerId ); environment.removeContainer( containerHost ); if ( environment.getContainerHostsByPeerId( containerHost.getPeerId() ).isEmpty() ) { EnvironmentPeer environmentPeer = environment.getEnvironmentPeer( containerHost.getPeerId() ); environment.removeEnvironmentPeer( containerHost.getPeerId() ); destroyTunnelToPeer( environmentPeer, environment ); } if ( environment.getEnvironmentPeers().isEmpty() ) { remove( environment ); notifyOnEnvironmentDestroyed( environmentId ); relationManager.removeRelation( environment ); cleanupEnvironment( environment.getEnvironmentId() ); } else { update( environment ); notifyOnContainerDestroyed( environment, containerId ); } relationManager.removeRelation( containerHost ); } @Override public void updateContainerHostname( final String environmentId, final String containerId, final String hostname ) throws EnvironmentNotFoundException, PeerException { Preconditions.checkState( !systemManager.isUpdateInProgress(), "System update in progress" ); final LocalEnvironment environment = ( LocalEnvironment ) loadEnvironment( environmentId ); EnvironmentContainerImpl containerHost = ( EnvironmentContainerImpl ) environment.getContainerHostById( containerId ); String oldHostname = containerHost.getHostname(); if ( oldHostname.equalsIgnoreCase( hostname ) ) { return; } containerHost.setHostname( hostname, true ); TrackerOperation operationTracker = tracker.createTrackerOperation( MODULE_NAME, String.format( "Propagating container hostname change in environment %s", environment.getName() ) ); final HostnameModificationWorkflow hostnameModificationWorkflow = new HostnameModificationWorkflow( environment, containerHost.getContainerId(), hostname, operationTracker, this, oldHostname ); registerActiveWorkflow( environment, hostnameModificationWorkflow ); hostnameModificationWorkflow.onStop( new Runnable() { @Override public void run() { removeActiveWorkflow( environment.getId() ); } } ); } @Override public Set<EnvironmentDto> getTenantEnvironments() { Set<Environment> environments = Sets.newHashSet(); // add local env-s environments.addAll( environmentService.getAll() ); try { // add bazaar env-s Set<BazaarEnvironment> bazaarEnvironments = environmentAdapter.getEnvironments( true ); // remove environments that exist onbazaar but don't exist on peer // workaround for https://github.com/subutai-io/base/issues/1464 removeStaleBazaarEnvironments( bazaarEnvironments ); environments.addAll( bazaarEnvironments ); // add remote env-s environments.addAll( getRemoteEnvironments( true ) ); } catch ( ActionFailedException e ) { //failed to obtainbazaar metadata, return all locally registered env-s environments.addAll( getRemoteEnvironments( true ) ); } Set<EnvironmentDto> environmentDtos = Sets.newHashSet(); for ( Environment environment : environments ) { EnvironmentDto environmentDto = new EnvironmentDto( environment.getId(), environment.getName(), environment.getStatus(), environment.getContainerDtos(), environment instanceof BazaarEnvironment || String.format( "Of %s", Common.BAZAAR_ID ) .equals( environment.getName() ) ? Common.BAZAAR_ID : Common.SUBUTAI_ID, getEnvironmentOwnerName( environment ) ); environmentDtos.add( environmentDto ); } return environmentDtos; } @Override public String getEnvironmentOwnerName( Environment environment ) { if ( environment instanceof RemoteEnvironment ) { RemoteEnvironment remoteEnvironment = ( RemoteEnvironment ) environment; boolean isBzrEnv = Objects.equals( remoteEnvironment.getInitiatorPeerId(), Common.BAZAAR_ID ); if ( isBzrEnv ) { return remoteEnvironment.getUsername() == null ? Common.BAZAAR_ID : String.format( "%s@%s", remoteEnvironment.getUsername(), remoteEnvironment.getRemoteUserId() ); } else { return remoteEnvironment.getUsername() == null ? REMOTE_OWNER_NAME : remoteEnvironment.getUsername(); } } else if ( environment instanceof BazaarEnvironment ) { BazaarEnvironment bazaarEnvironment = ( ( BazaarEnvironment ) environment ); return String.format( "%s@%s", bazaarEnvironment.getOwner(), bazaarEnvironment.getOwnerbazaarId() ); } User user = ServiceLocator.lookup( IdentityManager.class ).getUser( environment.getUserId() ); if ( user == null ) { return UKNOWN_OWNER_NAME; } else { return user.getUserName(); } } @Override public void onRegistrationSucceeded() { //let peer registration complete before sending environments for the first time TaskUtil.sleep( TimeUnit.SECONDS.toMillis( 10 ) ); //upload local environments tobazaar uploadPeerOwnerEnvironmentsToBazaar(); } @Override public void onUnregister() { Set<LocalEnvironment> envs = new HashSet<>(); envs.addAll( environmentService.getAll() ); for ( Iterator<LocalEnvironment> iterator = envs.iterator(); iterator.hasNext(); ) { LocalEnvironment environment = iterator.next(); if ( environment.isUploaded() ) { environment.markAsNotUploaded(); environmentService.merge( environment ); } } } // remove environments that exist onbazaar but don't exist on peer // workaround for https://github.com/subutai-io/base/issues/1464 private void removeStaleBazaarEnvironments( Set<BazaarEnvironment> bazaarEnvironments ) { try { ReservedNetworkResources networkResources = peerManager.getLocalPeer().getReservedNetworkResources(); for ( Iterator<BazaarEnvironment> iterator = bazaarEnvironments.iterator(); iterator.hasNext(); ) { BazaarEnvironment environment = iterator.next(); if ( networkResources.findByEnvironmentId( environment.getId() ) == null ) { iterator.remove(); } } } catch ( PeerException e ) { LOG.error( "Error removing stale Bazaar environments: {}", e.getMessage() ); } } private Set<RemoteEnvironment> getRemoteEnvironments( boolean includeBazaarEnvironments ) { Set<RemoteEnvironment> remoteEnvironments = Sets.newHashSet(); try { ReservedNetworkResources networkResources = peerManager.getLocalPeer().getReservedNetworkResources(); for ( NetworkResource networkResource : networkResources.getNetworkResources() ) { // exclude local reservations if ( !peerManager.getLocalPeer().getId().equals( networkResource.getInitiatorPeerId() ) ) { if ( !includeBazaarEnvironments && Common.BAZAAR_ID.equals( networkResource.getInitiatorPeerId() ) ) { continue; } RemotePeer initiatorPeer = networkResource.getInitiatorPeerId() == null ? null : peerManager.findPeer( networkResource.getInitiatorPeerId() ); remoteEnvironments.add( new RemoteEnvironment( networkResource, String.format( "Of %s", initiatorPeer == null ? networkResource.getInitiatorPeerId() : initiatorPeer.getName() ), peerManager.getLocalPeer() .findContainersByEnvironmentId( networkResource.getEnvironmentId() ) ) ); } } } catch ( PeerException e ) { LOG.error( "Error getting remote environments: {}", e.getMessage() ); } return remoteEnvironments; } public Set<RemoteEnvironment> getLocallyRegisteredBazaarEnvironments() { Set<RemoteEnvironment> bazaarEnvironments = Sets.newHashSet(); try { ReservedNetworkResources networkResources = peerManager.getLocalPeer().getReservedNetworkResources(); for ( NetworkResource networkResource : networkResources.getNetworkResources() ) { if ( Common.BAZAAR_ID.equals( networkResource.getInitiatorPeerId() ) ) { bazaarEnvironments.add( new RemoteEnvironment( networkResource, Common.BAZAAR_ID, peerManager.getLocalPeer() .findContainersByEnvironmentId( networkResource.getEnvironmentId() ) ) ); } } } catch ( PeerException e ) { LOG.error( "Error getting locally registered Bazaar environments: {}", e.getMessage() ); } return bazaarEnvironments; } private class BackgroundTasksRunner implements Runnable { @Override public void run() { LOG.debug( "Environment background tasks started..." ); syncEnvironments(); resetP2pKeys(); checkContainerDiskUsage(); LOG.debug( "Environment background tasks finished." ); } } private void checkContainerDiskUsage() { if ( System.currentTimeMillis() - lastContainerDiskUsageCheckTs >= TimeUnit.MINUTES .toMillis( CONTAINER_DISK_USAGE_CHECK_INTERVAL_MIN ) ) { lastContainerDiskUsageCheckTs = System.currentTimeMillis(); Subject.doAs( systemUser, new PrivilegedAction<Void>() { @Override public Void run() { doCheckContainerDiskUsage(); return null; } } ); } } private void resetP2pKeys() { if ( System.currentTimeMillis() - lastP2pSecretKeyResetTs >= TimeUnit.MINUTES .toMillis( RESET_ENVS_P2P_KEYS_INTERVAL_MIN ) ) { lastP2pSecretKeyResetTs = System.currentTimeMillis(); Subject.doAs( systemUser, new PrivilegedAction<Void>() { @Override public Void run() { doResetP2Pkeys(); return null; } } ); } } protected void doResetP2Pkeys() { try { //process only SS side environments for ( LocalEnvironment environment : environmentService.getAll() ) { if ( //process only healthy environments ( environment.getStatus() == EnvironmentStatus.HEALTHY || //or environments unhealthy due to p2p key reset ( environment.getStatus() == EnvironmentStatus.UNHEALTHY && Objects .equals( environment.getStatusDescription(), P2PSecretKeyModificationWorkflow.P2P_CAUSE ) ) ) && allContainersAreRunning( environment ) && ( System.currentTimeMillis() - environment.getCreationTimestamp() ) >= TimeUnit.MINUTES .toMillis( RESET_ENVS_P2P_KEYS_INTERVAL_MIN ) ) { final String secretKey = UUID.randomUUID().toString(); final long keyTtl = Common.DEFAULT_P2P_SECRET_KEY_TTL_SEC; resetP2PSecretKey( environment.getId(), secretKey, keyTtl, true ); } } } catch ( Exception e ) { LOG.warn( e.getMessage() ); } } private boolean allContainersAreRunning( final Environment environment ) { if ( CollectionUtil.isCollectionEmpty( environment.getContainerHosts() ) ) { return false; } for ( ContainerHost containerHost : environment.getContainerHosts() ) { try { ContainerHostInfo containerHostInfo = getHostRegistry().getContainerHostInfoById( containerHost.getId() ); if ( containerHostInfo.getState() != ContainerHostState.RUNNING ) { return false; } } catch ( HostDisconnectedException ignore ) { return false; } } return true; } protected HostRegistry getHostRegistry() { return ServiceLocator.lookup( HostRegistry.class ); } private void syncEnvironments() { if ( System.currentTimeMillis() - lastEnvSyncTs >= TimeUnit.MINUTES .toMillis( SYNC_ENVS_WITH_BAZAAR_INTERVAL_MIN ) ) { lastEnvSyncTs = System.currentTimeMillis(); Subject.doAs( systemUser, new PrivilegedAction<Void>() { @Override public Void run() { uploadPeerOwnerEnvironmentsToBazaar(); syncRemovedEnvironmentsWithBazaar(); return null; } } ); } } private void doCheckContainerDiskUsage() { getCachedExecutor().execute( new ContainerDiskUsageCheckTask( environmentAdapter.getBazaaarAdapter(), peerManager.getLocalPeer(), this ) ); } void uploadPeerOwnerEnvironmentsToBazaar() { getCachedExecutor() .execute( new UploadEnvironmentsTask( environmentAdapter, identityManager, environmentService, this ) ); } private void syncRemovedEnvironmentsWithBazaar() { getCachedExecutor().execute( new RemoveEnvironmentsTask( environmentAdapter, this, environmentService ) ); } private ContainerHost getContainerHostById( String containerId ) { try { return peerManager.getLocalPeer().getContainerHostById( containerId ); } catch ( HostNotFoundException e ) { return null; } } private ContainerHost getContainerHostByIp( String containerIp ) { try { return peerManager.getLocalPeer().getContainerHostByIp( containerIp ); } catch ( HostNotFoundException e ) { return null; } } private Set<Environment> getLocalEnvironments() { Set<Environment> environments = Sets.newHashSet(); environments.addAll( environmentService.getAll() ); setTransientFields( environments ); return environments; } public boolean rhHasEnvironments( String rhId ) { Preconditions.checkArgument( !StringUtils.isBlank( rhId ) ); for ( EnvironmentDto environment : getTenantEnvironments() ) { for ( ContainerDto container : environment.getContainers() ) { if ( rhId.equalsIgnoreCase( container.getRhId() ) ) { return true; } } } return false; } @Override public void onContainerHostnameChanged( final ContainerHostInfo containerInfo, final String previousHostname, final String currentHostname ) { boolean environmentFound = false; ContainerHost containerHost = getContainerHostById( containerInfo.getId() ); if ( containerHost == null ) { return; } Set<Environment> environments = getLocalEnvironments(); for ( Environment environment : environments ) { try { EnvironmentContainerImpl environmentContainerHost = ( EnvironmentContainerImpl ) environment.getContainerHostById( containerInfo.getId() ); environmentFound = true; updateContainerHostname( environment.getId(), environmentContainerHost.getId(), currentHostname ); } catch ( ContainerHostNotFoundException e ) { //ignore } catch ( EnvironmentNotFoundException | PeerException e ) { LOG.error( "Error updating container hostname: {}", e.getMessage() ); break; } } if ( !environmentFound && !Common.BAZAAR_ID.equals( containerHost.getInitiatorPeerId() ) ) { try { Peer peer = peerManager.getPeer( containerHost.getInitiatorPeerId() ); if ( peer instanceof RemotePeer ) { ( ( RemotePeer ) peer ) .updateContainerHostname( containerHost.getEnvironmentId().getId(), containerHost.getId(), currentHostname ); } } catch ( PeerException e ) { LOG.error( "Error updating container hostname on remote peer: {}", e.getMessage() ); } } else if ( !environmentFound ) { //bazaar environment environmentAdapter.handleHostnameChange( containerInfo, previousHostname, currentHostname ); } } @Override public void onContainerDestroyed( final ContainerHost containerHost ) { boolean environmentFound = false; Set<Environment> environments = getLocalEnvironments(); for ( final Environment environment : environments ) { try { //remote container metadata EnvironmentContainerImpl environmentContainerHost = ( EnvironmentContainerImpl ) environment.getContainerHostById( containerHost.getId() ); environmentFound = true; Environment env = environmentContainerHost.destroy( true ); //if environment got empty, remove environment metadata if ( env.getContainerHosts().isEmpty() ) { remove( ( LocalEnvironment ) env ); notifyOnEnvironmentDestroyed( env.getId() ); relationManager.removeRelation( env ); Subject.doAs( systemUser, new PrivilegedAction<Void>() { @Override public Void run() { cleanupEnvironment( environment.getEnvironmentId() ); return null; } } ); } else { notifyOnContainerDestroyed( env, containerHost.getId() ); } //remove security relation relationManager.removeRelation( containerHost ); break; } catch ( ContainerHostNotFoundException e ) { // ignore } catch ( PeerException e ) { LOG.error( "Error processing container destroy event: {}", e.getMessage() ); break; } } //process an x-peer environment RemoteEnvironment xPeerEnvironment = null; if ( !environmentFound && !Common.BAZAAR_ID.equals( containerHost.getInitiatorPeerId() ) ) { Set<RemoteEnvironment> remoteEnvironments = getRemoteEnvironments( false ); for ( RemoteEnvironment remoteEnvironment : remoteEnvironments ) { if ( remoteEnvironment.getId().equals( containerHost.getEnvironmentId().getId() ) ) { xPeerEnvironment = remoteEnvironment; break; } } } if ( xPeerEnvironment != null ) { //if this is the only container in a remote environment //we need to remove the environment //environment.getContainerDtos() is used b/c getContainers exposes containers to owner only if ( xPeerEnvironment.getContainerDtos().isEmpty() || ( xPeerEnvironment.getContainerDtos().size() == 1 && containerHost.getId().equals( xPeerEnvironment.getContainerDtos().iterator().next().getId() ) ) ) { cleanupEnvironment( xPeerEnvironment.getEnvironmentId() ); } //notify remote peer about container destruction try { Peer peer = peerManager.getPeer( containerHost.getInitiatorPeerId() ); if ( peer instanceof RemotePeer ) { ( ( RemotePeer ) peer ).excludeContainerFromEnvironment( containerHost.getEnvironmentId().getId(), containerHost.getId() ); } } catch ( PeerException e ) { LOG.error( "Error excluding container from environment on remote peer: {}", e.getMessage() ); } } } @Override public Set<String> getDeletedEnvironmentsFromBazaar() { return environmentAdapter.getDeletedEnvironmentsIds(); } //called by local client @Override public void placeEnvironmentInfoByContainerIp( final String containerIp ) throws PeerException, CommandException { ContainerHost containerHost = getContainerHostByIp( containerIp ); if ( containerHost == null ) { throw new ContainerHostNotFoundException( "Container not found by ip " + containerIp ); } Set<EnvironmentDto> environmentDtos = getTenantEnvironments(); for ( EnvironmentDto environmentDto : environmentDtos ) { //skip remote env-s if ( !REMOTE_OWNER_NAME.equalsIgnoreCase( environmentDto.getUsername() ) ) { for ( ContainerDto containerDto : environmentDto.getContainers() ) { if ( containerIp.equals( containerDto.getIp() ) ) { placeInfoIntoContainer( environmentDto, containerHost ); return; } } } } try { RemotePeer peer = peerManager.findPeer( containerHost.getInitiatorPeerId() ); if ( peer != null ) { peer.placeEnvironmentInfoByContainerId( containerHost.getEnvironmentId().getId(), containerHost.getId() ); } } catch ( PeerException e ) { LOG.error( "Error requesting placement of environment info on remote peer: {}", e.getMessage() ); for ( EnvironmentDto environmentDto : environmentDtos ) { if ( REMOTE_OWNER_NAME.equalsIgnoreCase( environmentDto.getUsername() ) ) { for ( ContainerDto containerDto : environmentDto.getContainers() ) { if ( containerIp.equals( containerDto.getIp() ) ) { placeInfoIntoContainer( environmentDto, containerHost ); return; } } } } //rethrow error if env metadata not found throw e; } } @Override public Environment getEnvironment( String environmentId ) { return environmentService.find( environmentId ); } //called by remote peer @Override public void placeEnvironmentInfoByContainerId( final String environmentId, final String containerId ) throws EnvironmentNotFoundException, ContainerHostNotFoundException, CommandException { final LocalEnvironment environment = environmentService.find( environmentId ); if ( environment == null ) { throw new EnvironmentNotFoundException(); } EnvironmentContainerImpl containerHost = ( EnvironmentContainerImpl ) environment.getContainerHostById( containerId ); setTransientFields( Sets.<Environment>newHashSet( environment ) ); EnvironmentDto environmentDto = new EnvironmentDto( environment.getId(), environment.getName(), environment.getStatus(), environment.getContainerDtos(), environment instanceof BazaarEnvironment || String.format( "Of %s", Common.BAZAAR_ID ) .equals( environment.getName() ) ? Common.BAZAAR_ID : Common.SUBUTAI_ID, getEnvironmentOwnerName( environment ) ); placeInfoIntoContainer( environmentDto, containerHost ); } private void placeInfoIntoContainer( EnvironmentDto environmentDto, ContainerHost containerHost ) throws CommandException { if ( containerHost instanceof EnvironmentContainerImpl ) { // workaround to disable security checks for this call ( ( EnvironmentContainerImpl ) containerHost ).executeUnsafe( new RequestBuilder( String.format( "rm /root/env ; echo '%s' > /root/env", JsonUtil.toJson( environmentDto ) ) ) ); } else { containerHost.execute( new RequestBuilder( String.format( "rm /root/env ; echo '%s' > /root/env", JsonUtil.toJson( environmentDto ) ) ) ); } } public void cleanupEnvironment( EnvironmentId environmentId ) { try { peerManager.getLocalPeer().cleanupEnvironment( environmentId ); } catch ( PeerException e ) { LOG.warn( "Error cleaning up environment: {}", e.getMessage() ); } } private void destroyTunnelToPeer( EnvironmentPeer environmentPeer, Environment environment ) { P2pIps p2pIps = new P2pIps(); p2pIps.addP2pIps( environmentPeer.getRhP2pIps() ); try { peerManager.getLocalPeer().deleteTunnels( p2pIps, environment.getEnvironmentId() ); } catch ( PeerException e ) { LOG.error( "Error destroying tunnels to peer {}: {}", environmentPeer.getPeerId(), e.getMessage() ); } } }