@Test
  public void testAddChild() throws Exception {
    try {
      // to test in GUI:
      // services: [ { type: org.apache.brooklyn.entity.stock.BasicEntity }]
      Response response =
          client()
              .path(entityEndpoint + "/children")
              .query("timeout", "10s")
              .post(
                  javax.ws.rs.client.Entity.entity(
                      "services: [ { type: " + TestEntity.class.getName() + " }]",
                      "application/yaml"));

      HttpAsserts.assertHealthyStatusCode(response.getStatus());
      Assert.assertEquals(entity.getChildren().size(), 1);
      Entity child = Iterables.getOnlyElement(entity.getChildren());
      Assert.assertTrue(Entities.isManaged(child));

      TaskSummary task = response.readEntity(TaskSummary.class);
      Assert.assertEquals(task.getResult(), MutableList.of(child.getId()));

    } finally {
      // restore it for other tests
      Collection<Entity> children = entity.getChildren();
      if (!children.isEmpty()) Entities.unmanage(Iterables.getOnlyElement(children));
    }
  }
Example #2
0
  /** De-register our {@link MesosLocation} and its children. */
  @Override
  public void stop() {
    disconnectSensors();

    sensors().set(SERVICE_UP, Boolean.FALSE);

    deleteLocation();

    Duration timeout = config().get(SHUTDOWN_TIMEOUT);

    // Find all applications and stop, blocking for up to five minutes until ended
    try {
      Iterable<Entity> entities =
          Iterables.filter(
              getManagementContext().getEntityManager().getEntities(),
              Predicates.and(
                  MesosUtils.sameCluster(this),
                  Predicates.not(EntityPredicates.applicationIdEqualTo(getApplicationId()))));
      Set<Application> applications =
          ImmutableSet.copyOf(
              Iterables.transform(
                  entities,
                  new Function<Entity, Application>() {
                    @Override
                    public Application apply(Entity input) {
                      return input.getApplication();
                    }
                  }));
      LOG.debug("Stopping applications: {}", Iterables.toString(applications));
      Entities.invokeEffectorList(this, applications, Startable.STOP).get(timeout);
    } catch (Exception e) {
      LOG.warn("Error stopping applications", e);
    }

    // Stop all framework tasks in parallel
    try {
      Group frameworks = sensors().get(MESOS_FRAMEWORKS);
      LOG.debug("Stopping framework tasks in: {}", Iterables.toString(frameworks.getMembers()));
      Entities.invokeEffectorList(this, frameworks.getMembers(), Startable.STOP).get(timeout);
    } catch (Exception e) {
      LOG.warn("Error stopping frameworks", e);
    }

    // Stop anything else left over
    // TODO Stop slave entities
    try {
      super.stop();
    } catch (Exception e) {
      LOG.warn("Error stopping children", e);
    }
  }
  // Test reproduces functionality used in Monterey, for Venue entity being told of requestActor
  @Test
  public void testSubscribeToJmxNotificationAndEmitCorrespondingNotificationSensor()
      throws Exception {
    TestApplication app2 = new TestApplicationImpl();
    final EntityWithEmitter entity = new EntityWithEmitter(app2);
    Entities.startManagement(app2);
    try {
      app2.start(ImmutableList.of(new SimulatedLocation()));

      final List<SensorEvent<String>> received = Lists.newArrayList();
      app2.subscriptions()
          .subscribe(
              null,
              EntityWithEmitter.MY_NOTIF,
              new SensorEventListener<String>() {
                public void onEvent(SensorEvent<String> event) {
                  received.add(event);
                }
              });

      final StandardEmitterMBean mbean =
          jmxService.registerMBean(ImmutableList.of("one"), objectName);
      final AtomicInteger sequence = new AtomicInteger(0);

      jmxHelper.connect(TIMEOUT_MS);
      jmxHelper.addNotificationListener(
          jmxObjectName,
          new NotificationListener() {
            public void handleNotification(Notification notif, Object callback) {
              if (notif.getType().equals("one")) {
                entity.sensors().emit(EntityWithEmitter.MY_NOTIF, (String) notif.getUserData());
              }
            }
          });

      Asserts.succeedsEventually(
          ImmutableMap.of("timeout", TIMEOUT_MS),
          new Runnable() {
            public void run() {
              sendNotification(mbean, "one", sequence.getAndIncrement(), "abc");
              assertTrue(received.size() > 0, "received size should be bigger than 0");
              assertEquals(received.get(0).getValue(), "abc");
            }
          });
    } finally {
      Entities.destroyAll(app2.getManagementContext());
    }
  }
  /*TODO RENAME Method. It could be represent that the service is bound and the service
  operation is called*/
  private void manageService(Entity rawEntity) {

    CloudFoundryService cloudFoundryService;
    if (rawEntity instanceof CloudFoundryService) {

      cloudFoundryService = (CloudFoundryService) rawEntity;

      String serviceName = cloudFoundryService.getConfig(CloudFoundryService.SERVICE_INSTANCE_NAME);

      if (!Strings.isEmpty(serviceName)) {

        Entities.waitForServiceUp(
            cloudFoundryService, cloudFoundryService.getConfig(BrooklynConfigKeys.START_TIMEOUT));

        bindingServiceToEntity(serviceName);
        setCredentialsOnService(cloudFoundryService);
        cloudFoundryService.operation(getEntity());
      } else {
        log.error(
            "Trying to get service instance name from {}, but getting null", cloudFoundryService);
      }
    } else {
      log.error(
          "The service entity {} is not available from the application {}",
          new Object[] {rawEntity, getEntity()});

      throw new NoSuchElementException(
          "No entity matching id "
              + rawEntity.getId()
              + " in Management Context "
              + getEntity().getManagementContext()
              + " during entity service binding "
              + getEntity().getId());
    }
  }
  @Override
  public void initApp() {
    StringConfigMap config = getManagementContext().getConfig();

    GeoscalingDnsService geoDns =
        addChild(
            EntitySpec.create(GeoscalingDnsService.class)
                .displayName("GeoScaling DNS")
                .configure(
                    "username",
                    checkNotNull(config.getFirst("brooklyn.geoscaling.username"), "username"))
                .configure(
                    "password",
                    checkNotNull(config.getFirst("brooklyn.geoscaling.password"), "password"))
                .configure(
                    "primaryDomainName",
                    checkNotNull(
                        config.getFirst("brooklyn.geoscaling.primaryDomain"), "primaryDomain"))
                .configure("smartSubdomainName", "brooklyn"));

    DynamicRegionsFabric webFabric =
        addChild(
            EntitySpec.create(DynamicRegionsFabric.class)
                .displayName("Web Fabric")
                .configure(DynamicRegionsFabric.FACTORY, new ElasticJavaWebAppService.Factory())

                // specify the WAR file to use
                .configure(
                    JavaWebAppService.ROOT_WAR, Entities.getRequiredUrlConfig(this, WAR_PATH)));

    // tell GeoDNS what to monitor
    geoDns.setTargetEntityProvider(webFabric);
  }
  @AfterMethod(alwaysRun = true)
  public void tearDown() throws Exception {
    List<Exception> exceptions = Lists.newArrayList();
    try {
      if (machines != null) {
        exceptions.addAll(releaseMachineSafely(machines));
        machines.clear();
      }
    } finally {
      try {
        if (managementContext != null) Entities.destroyAll(managementContext);
      } catch (Exception e) {
        LOG.warn("Error destroying management context", e);
        exceptions.add(e);
      }
    }

    // TODO Debate about whether to:
    //  - use destroyAllCatching (i.e. not propagating exception)
    //    Benefit is that other tests in class will subsequently be run, rather than bailing out.
    //  - propagate exceptions from tearDown
    //    Benefit is that we don't hide errors; release(...) etc should not be throwing exceptions.
    if (exceptions.size() > 0) {
      throw new CompoundRuntimeException("Error in tearDown of " + getClass(), exceptions);
    }
  }
 @Override
 public void preInstall() {
   resolver = Entities.newDownloader(this);
   String subpath = entity.getConfig(BrooklynNode.SUBPATH_IN_ARCHIVE);
   if (subpath == null) {
     // assume the dir name is `basename-VERSION` where download link is
     // `basename-VERSION-dist.tar.gz`
     String uploadUrl = entity.getConfig(BrooklynNode.DISTRO_UPLOAD_URL);
     String origDownloadName = uploadUrl;
     if (origDownloadName == null)
       origDownloadName = entity.getAttribute(BrooklynNode.DOWNLOAD_URL);
     if (origDownloadName != null) {
       // BasicDownloadResolver makes it crazy hard to get the template-evaluated value of
       // DOWNLOAD_URL
       origDownloadName =
           DownloadSubstituters.substitute(
               origDownloadName, DownloadSubstituters.getBasicEntitySubstitutions(this));
       origDownloadName = Urls.decode(origDownloadName);
       origDownloadName = Urls.getBasename(origDownloadName);
       String downloadName = origDownloadName;
       downloadName = Strings.removeFromEnd(downloadName, ".tar.gz");
       downloadName = Strings.removeFromEnd(downloadName, ".tgz");
       downloadName = Strings.removeFromEnd(downloadName, ".zip");
       if (!downloadName.equals(origDownloadName)) {
         downloadName = Strings.removeFromEnd(downloadName, "-dist");
         subpath = downloadName;
       }
     }
   }
   if (subpath == null) subpath = format("brooklyn-dist-%s", getVersion());
   setExpandedInstallDir(
       Os.mergePaths(getInstallDir(), resolver.getUnpackedDirectoryName(subpath)));
 }
Example #8
0
  @Override
  public void release(DockerContainerLocation machine) {
    lock.readLock().lock();
    try {
      LOG.info("Releasing {}", machine);

      DynamicCluster cluster = dockerHost.getDockerContainerCluster();
      DockerContainer container = machine.getOwner();
      if (cluster.removeMember(container)) {
        LOG.info("Docker Host {}: member {} released", dockerHost.getDockerHostName(), machine);
      } else {
        LOG.warn(
            "Docker Host {}: member {} not found for release",
            dockerHost.getDockerHostName(),
            machine);
      }

      // Now close and unmange the container
      try {
        machine.close();
        container.stop();
      } catch (Exception e) {
        LOG.warn("Error stopping container: " + container, e);
        Exceptions.propagateIfFatal(e);
      } finally {
        Entities.unmanage(container);
      }
    } finally {
      lock.readLock().unlock();
    }
  }
Example #9
0
  @Override
  public void doStart(Collection<? extends Location> locs) {
    List<Location> locations = MutableList.of();

    sensors().set(SERVICE_UP, Boolean.FALSE);
    ServiceStateLogic.setExpectedState(this, Lifecycle.STARTING);

    LOG.info("Creating new MesosLocation");
    createLocation(MutableMap.<String, Object>of());

    // Start frameworks
    try {
      Group frameworks = sensors().get(MESOS_FRAMEWORKS);
      Entities.invokeEffectorList(
              this,
              frameworks.getMembers(),
              Startable.START,
              ImmutableMap.of("locations", locations))
          .getUnchecked();
    } catch (Exception e) {
      LOG.warn("Error starting frameworks", e);
      ServiceStateLogic.setExpectedState(this, Lifecycle.ON_FIRE);
      Exceptions.propagate(e);
    }

    super.doStart(locations);

    connectSensors();

    ServiceStateLogic.setExpectedState(this, Lifecycle.RUNNING);
    sensors().set(SERVICE_UP, Boolean.TRUE);
  }
 @AfterMethod(alwaysRun = true)
 public void tearDown() throws Exception {
   if (feed != null) feed.stop();
   if (jmxHelper != null) jmxHelper.disconnect();
   if (jmxService != null) jmxService.shutdown();
   if (app != null) Entities.destroyAll(app.getManagementContext());
   feed = null;
 }
  protected WinRmExecuteHelper newScript(Map<String, ?> flags, String phase) {
    if (!Entities.isManaged(getEntity()))
      throw new IllegalStateException(
          getEntity() + " is no longer managed; cannot create script to run here (" + phase + ")");

    WinRmExecuteHelper s = new WinRmExecuteHelper(this, phase + " " + elvis(entity, this));
    return s;
  }
  @Override
  public void init() {
    super.init();

    getMutableEntityType()
        .addEffector(
            EXECUTE_SCRIPT,
            new EffectorBody<String>() {
              @Override
              public String call(ConfigBag parameters) {
                return executeScript((String) parameters.getStringKey("commands"));
              }
            });

    Entities.checkRequiredUrl(this, getCassandraConfigTemplateUrl());
    Entities.getRequiredUrlConfig(this, CASSANDRA_RACKDC_CONFIG_TEMPLATE_URL);

    connectEnrichers();
  }
 @Override
 public String getRpcAddress() {
   String sensorName = getConfig(RPC_ADDRESS_SENSOR);
   if (Strings.isNonBlank(sensorName))
     return Entities.submit(
             this,
             DependentConfiguration.attributeWhenReady(this, Sensors.newStringSensor(sensorName)))
         .getUnchecked();
   return "0.0.0.0";
 }
  protected void runStopProcessAndRestart(Effector<?> restartEffector, Map<String, ?> args)
      throws Exception {
    LocalhostMachineProvisioningLocation loc = app.newLocalhostProvisioningLocation();
    SoftwareProcess entity = app.createAndManageChild(newEntitySpec());

    // Start the app
    app.start(ImmutableList.of(loc));
    EntityTestUtils.assertAttributeEqualsEventually(entity, SoftwareProcess.SERVICE_UP, true);
    EntityTestUtils.assertAttributeEqualsEventually(app, SoftwareProcess.SERVICE_UP, true);

    // Stop the process
    Entities.invokeEffector(
            app,
            entity,
            SoftwareProcess.STOP,
            ImmutableMap.of(
                StopSoftwareParameters.STOP_MACHINE_MODE.getName(),
                StopSoftwareParameters.StopMode.NEVER))
        .get();
    EntityTestUtils.assertAttributeEqualsEventually(entity, SoftwareProcess.SERVICE_UP, false);
    EntityTestUtils.assertAttributeEqualsEventually(
        entity, SoftwareProcess.SERVICE_STATE_ACTUAL, Lifecycle.STOPPED);
    EntityTestUtils.assertAttributeEqualsEventually(
        entity, SoftwareProcess.SERVICE_PROCESS_IS_RUNNING, false);
    EntityTestUtils.assertAttributeEventually(
        entity,
        ServiceStateLogic.SERVICE_NOT_UP_INDICATORS,
        CollectionFunctionals.<String>mapSizeEquals(1));

    // Restart the process
    Entities.invokeEffector(app, entity, restartEffector, args).get();
    EntityTestUtils.assertAttributeEqualsEventually(entity, SoftwareProcess.SERVICE_UP, true);
    EntityTestUtils.assertAttributeEqualsEventually(
        entity, SoftwareProcess.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING);
    EntityTestUtils.assertAttributeEqualsEventually(
        entity, SoftwareProcess.SERVICE_PROCESS_IS_RUNNING, true);
    EntityTestUtils.assertAttributeEqualsEventually(
        entity, ServiceStateLogic.SERVICE_NOT_UP_INDICATORS, ImmutableMap.<String, Object>of());

    EntityTestUtils.assertAttributeEqualsEventually(app, SoftwareProcess.SERVICE_UP, true);
    EntityTestUtils.assertAttributeEqualsEventually(
        app, SoftwareProcess.SERVICE_STATE_ACTUAL, Lifecycle.RUNNING);
  }
  @Override
  public String getBroadcastAddress() {
    String sensorName = getConfig(BROADCAST_ADDRESS_SENSOR);
    if (Strings.isNonBlank(sensorName))
      return Entities.submit(
              this,
              DependentConfiguration.attributeWhenReady(this, Sensors.newStringSensor(sensorName)))
          .getUnchecked();

    String snitchName = getConfig(CassandraNode.ENDPOINT_SNITCH_NAME);
    if (snitchName.equals("Ec2MultiRegionSnitch") || snitchName.contains("MultiCloudSnitch")) {
      // http://www.datastax.com/documentation/cassandra/2.0/mobile/cassandra/architecture/architectureSnitchEC2MultiRegion_c.html
      // describes that the listen_address is set to the private IP, and the broadcast_address is
      // set to the public IP.
      return getAttribute(CassandraNode.ADDRESS);
    } else if (!getDriver().isClustered()) {
      return getListenAddress();
    } else {
      // In other situations, prefer the hostname, so other regions can see it
      // *Unless* hostname resolves at the target to a local-only interface which is different to
      // ADDRESS
      // (workaround for issue deploying to localhost)
      String hostname = getAttribute(CassandraNode.HOSTNAME);
      try {
        String resolvedAddress = getDriver().getResolvedAddress(hostname);
        if (resolvedAddress == null) {
          log.debug(
              "Cassandra using broadcast address "
                  + getListenAddress()
                  + " for "
                  + this
                  + " because hostname "
                  + hostname
                  + " could not be resolved at remote machine");
          return getListenAddress();
        }
        if (resolvedAddress.equals("127.0.0.1")) {
          log.debug(
              "Cassandra using broadcast address "
                  + getListenAddress()
                  + " for "
                  + this
                  + " because hostname "
                  + hostname
                  + " resolves to 127.0.0.1");
          return getListenAddress();
        }
        return hostname;
      } catch (Exception e) {
        Exceptions.propagateIfFatal(e);
        log.warn("Error resolving hostname " + hostname + " for " + this + ": " + e, e);
        return hostname;
      }
    }
  }
Example #16
0
 @Override
 public void removeHost(DockerHost host) {
   SdnAgent agent = host.sensors().get(SdnAgent.SDN_AGENT);
   if (agent == null) {
     LOG.warn("{} cannot find calico service: {}", this, host);
     return;
   }
   agent.stop();
   getAgents().removeMember(agent);
   Entities.unmanage(agent);
   if (LOG.isDebugEnabled()) LOG.debug("{} removed calico plugin {}", this, agent);
 }
  @Override
  public String getListenAddress() {
    String sensorName = getConfig(LISTEN_ADDRESS_SENSOR);
    if (Strings.isNonBlank(sensorName))
      return Entities.submit(
              this,
              DependentConfiguration.attributeWhenReady(this, Sensors.newStringSensor(sensorName)))
          .getUnchecked();

    String subnetAddress = getAttribute(CassandraNode.SUBNET_ADDRESS);
    return Strings.isNonBlank(subnetAddress) ? subnetAddress : getAttribute(CassandraNode.ADDRESS);
  }
  @Test
  public void testEntityCreatingItsEnricherDoesNotReCreateItUnlessUniqueTagDifferent()
      throws Exception {
    TestEntity e1 =
        origApp.createAndManageChild(
            EntitySpec.create(TestEntity.class, MyTestEntityWithEnricher.class));
    Collection<Enricher> e1e = e1.getEnrichers();
    log.info("enrichers1: " + e1e);
    Entities.dumpInfo(e1);
    assertEquals(e1e.size(), 5);

    newApp = (TestApplication) rebind();
    Entity e2 =
        Iterables.getOnlyElement(
            Entities.descendants(newApp, EntityPredicates.idEqualTo(e1.getId())));
    Collection<Enricher> e2e = e2.getEnrichers();
    log.info("enrichers2: " + e2e);
    Entities.dumpInfo(e2);

    assertEquals(e2e.size(), e1e.size() + 1);
  }
  /** Test that a node starts and sets SERVICE_UP correctly. */
  @Test(groups = "Integration")
  public void canStartupAndShutdown() {
    solr = app.createAndManageChild(EntitySpec.create(SolrServer.class));
    app.start(ImmutableList.of(testLocation));

    EntityAsserts.assertAttributeEqualsEventually(solr, Startable.SERVICE_UP, true);
    Entities.dumpInfo(app);

    solr.stop();

    EntityAsserts.assertAttributeEqualsEventually(solr, Startable.SERVICE_UP, false);
  }
  @Override
  public void install() {
    Maybe<Object> url =
        ((EntityInternal) getEntity()).config().getRaw(SoftwareProcess.DOWNLOAD_URL);
    if (url.isPresentAndNonNull()) {
      DownloadResolver resolver = Entities.newDownloader(this);
      List<String> urls = resolver.getTargets();
      downloadedFilename = resolver.getFilename();

      List<String> commands = new LinkedList<String>();
      commands.addAll(BashCommands.commandsToDownloadUrlsAs(urls, downloadedFilename));
      commands.addAll(ArchiveUtils.installCommands(downloadedFilename));

      int result =
          newScript(ImmutableMap.of(INSTALL_INCOMPLETE, true), INSTALLING)
              .failOnNonZeroResultCode(false)
              .body
              .append(commands)
              .execute();

      if (result != 0) {
        // could not install at remote machine; try resolving URL here and copying across
        for (String urlI : urls) {
          result =
              ArchiveUtils.install(
                  getMachine(), urlI, Urls.mergePaths(getInstallDir(), downloadedFilename));
          if (result == 0) break;
        }
        if (result != 0)
          throw new IllegalStateException("Error installing archive: " + downloadedFilename);
      }
    }

    // If downloadUrl did partial install (see INSTALL_INCOMPLETE above) then always execute install
    // so mark it as completed.
    String installCommand = getEntity().getConfig(VanillaSoftwareProcess.INSTALL_COMMAND);
    if (url.isPresentAndNonNull() && Strings.isBlank(installCommand))
      installCommand = "# mark as complete";

    if (Strings.isNonBlank(installCommand)) {
      newScript(INSTALLING)
          .failOnNonZeroResultCode()
          .environmentVariablesReset(getShellEnvironment())
          .body
          .append(installCommand)
          .execute();
    }
  }
  public static void main(String[] argv) {
    List<String> args = Lists.newArrayList(argv);
    String port = CommandLineUtil.getCommandLineOption(args, "--port", "8081+");
    String locations =
        CommandLineUtil.getCommandLineOption(
            args, "--locations", Joiner.on(",").join(DEFAULT_LOCATIONS));

    BrooklynLauncher launcher =
        BrooklynLauncher.newInstance()
            .application(
                EntitySpec.create(StartableApplication.class, GlobalWebFabricExample.class)
                    .displayName("Brooklyn Global Web Fabric Example"))
            .webconsolePort(port)
            .locations(Arrays.asList(locations))
            .start();

    Entities.dumpInfo(launcher.getApplications());
  }
 @AfterMethod(alwaysRun = true)
 public void tearDown() {
   if (app != null) Entities.destroyAll(app.getManagementContext());
   app = null;
 }
 @AfterMethod(alwaysRun = true)
 public void tearDown() throws Exception {
   if (app != null) Entities.destroyAllCatching(app.getManagementContext());
 }
  protected void doStop(ConfigBag parameters, Callable<StopMachineDetails<Integer>> stopTask) {
    preStopConfirmCustom();

    log.info("Stopping {} in {}", entity(), entity().getLocations());

    StopMode stopMachineMode = getStopMachineMode(parameters);
    StopMode stopProcessMode = parameters.get(StopSoftwareParameters.STOP_PROCESS_MODE);

    DynamicTasks.queue("pre-stop", new PreStopCustomTask());

    // BROOKLYN-263:
    // With this change the stop effector will wait for Location to provision so it can terminate
    // the machine, if a provisioning request is in-progress.
    //
    // The ProvisionMachineTask stores transient internal state in PROVISIONING_TASK_STATE and
    // PROVISIONED_MACHINE: it records when the provisioning is running and when done; and it
    // records the final machine. We record the machine in the internal sensor (rather than
    // just relying on getLocations) because the latter is set much later in the start()
    // process.
    //
    // This code is a big improvement (previously there was a several-minute window in some
    // clouds where a call to stop() would leave the machine running).
    //
    // However, there are still races. If the start() code has not yet reached the call to
    // location.obtain() then we won't wait, and the start() call won't know to abort. It's
    // fiddly to get that right, because we need to cope with restart() - so we mustn't leave
    // any state behind that will interfere with subsequent sequential calls to start().
    // There is some attempt to handle it by ProvisionMachineTask checking if the expectedState
    // is stopping/stopped.
    Maybe<MachineLocation> machine = Machines.findUniqueMachineLocation(entity().getLocations());
    ProvisioningTaskState provisioningState =
        entity().sensors().get(AttributesInternal.INTERNAL_PROVISIONING_TASK_STATE);

    if (machine.isAbsent() && provisioningState == ProvisioningTaskState.RUNNING) {
      Duration maxWait = entity().config().get(STOP_WAIT_PROVISIONING_TIMEOUT);
      log.info(
          "When stopping {}, waiting for up to {} for the machine to finish provisioning, before terminating it",
          entity(),
          maxWait);
      boolean success =
          Repeater.create("Wait for a machine to appear")
              .until(
                  new Callable<Boolean>() {
                    @Override
                    public Boolean call() throws Exception {
                      ProvisioningTaskState state =
                          entity()
                              .sensors()
                              .get(AttributesInternal.INTERNAL_PROVISIONING_TASK_STATE);
                      return (state != ProvisioningTaskState.RUNNING);
                    }
                  })
              .backoffTo(Duration.FIVE_SECONDS)
              .limitTimeTo(maxWait)
              .run();
      if (!success) {
        log.warn(
            "When stopping {}, timed out after {} waiting for the machine to finish provisioning - machine may we left running",
            entity(),
            maxWait);
      }
      machine = Maybe.ofDisallowingNull(entity().sensors().get(INTERNAL_PROVISIONED_MACHINE));
    }
    entity().sensors().remove(AttributesInternal.INTERNAL_PROVISIONING_TASK_STATE);
    entity().sensors().remove(INTERNAL_PROVISIONED_MACHINE);

    Task<List<?>> stoppingProcess = null;
    if (canStop(stopProcessMode, entity())) {
      stoppingProcess =
          Tasks.parallel(
              "stopping",
              Tasks.create("stopping (process)", new StopProcessesAtMachineTask()),
              Tasks.create("stopping (feeds)", new StopFeedsAtMachineTask()));
      DynamicTasks.queue(stoppingProcess);
    }

    Task<StopMachineDetails<Integer>> stoppingMachine = null;
    if (canStop(stopMachineMode, machine.isAbsent())) {
      // Release this machine (even if error trying to stop process - we rethrow that after)
      Map<String, Object> stopMachineFlags = MutableMap.of();
      if (Entitlements.getEntitlementContext() != null) {
        stopMachineFlags.put(
            "tags",
            MutableSet.of(
                BrooklynTaskTags.tagForEntitlement(Entitlements.getEntitlementContext())));
      }
      Task<StopMachineDetails<Integer>> stopMachineTask =
          Tasks.<StopMachineDetails<Integer>>builder()
              .displayName("stopping (machine)")
              .body(stopTask)
              .flags(stopMachineFlags)
              .build();
      stoppingMachine = DynamicTasks.queue(stopMachineTask);

      DynamicTasks.drain(entity().getConfig(STOP_PROCESS_TIMEOUT), false);

      // shutdown the machine if stopping process fails or takes too long
      synchronized (stoppingMachine) {
        // task also used as mutex by DST when it submits it; ensure it only submits once!
        if (!stoppingMachine.isSubmitted()) {
          // force the stoppingMachine task to run by submitting it here
          StringBuilder msg =
              new StringBuilder("Submitting machine stop early in background for ")
                  .append(entity());
          if (stoppingProcess == null) {
            msg.append(". Process stop skipped, pre-stop not finished?");
          } else {
            msg.append(" because process stop has ")
                .append((stoppingProcess.isDone() ? "finished abnormally" : "not finished"));
          }
          log.warn(msg.toString());
          Entities.submit(entity(), stoppingMachine);
        }
      }
    }

    try {
      // This maintains previous behaviour of silently squashing any errors on the stoppingProcess
      // task if the
      // stoppingMachine exits with a nonzero value
      boolean checkStopProcesses =
          (stoppingProcess != null
              && (stoppingMachine == null || stoppingMachine.get().value == 0));

      if (checkStopProcesses) {
        // TODO we should test for destruction above, not merely successful "stop", as things like
        // localhost and ssh won't be destroyed
        DynamicTasks.waitForLast();
        if (machine.isPresent()) {
          // throw early errors *only if* there is a machine and we have not destroyed it
          stoppingProcess.get();
        }
      }
    } catch (Throwable e) {
      ServiceStateLogic.setExpectedState(entity(), Lifecycle.ON_FIRE);
      Exceptions.propagate(e);
    }
    entity().sensors().set(SoftwareProcess.SERVICE_UP, false);
    ServiceStateLogic.setExpectedState(entity(), Lifecycle.STOPPED);

    DynamicTasks.queue("post-stop", new PostStopCustomTask());

    if (log.isDebugEnabled()) log.debug("Stopped software process entity " + entity());
  }
 @AfterMethod(alwaysRun = true)
 public void tearDown() throws Exception {
   if (managementContext != null) Entities.destroyAll(managementContext);
 }
Example #26
0
  @Override
  public DockerContainerLocation obtain(Map<?, ?> flags) throws NoMachinesAvailableException {
    lock.readLock().lock();
    try {
      // Lookup entity from context or flags
      Object context = flags.get(LocationConfigKeys.CALLER_CONTEXT.getName());
      if (context == null || !(context instanceof Entity)) {
        throw new IllegalStateException("Invalid location context: " + context);
      }
      Entity entity = (Entity) context;

      // Flag to configure adding SSHable layer
      boolean useSsh =
          entity.config().get(DockerContainer.DOCKER_USE_SSH)
              && dockerHost.config().get(DockerContainer.DOCKER_USE_SSH);

      // Configure the entity
      LOG.info("Configuring entity {} via subnet {}", entity, dockerHost.getSubnetTier());
      entity
          .config()
          .set(
              SubnetTier.PORT_FORWARDING_MANAGER,
              dockerHost.getSubnetTier().getPortForwardManager());
      entity.config().set(SubnetTier.PORT_FORWARDER, portForwarder);
      if (getOwner().config().get(SdnAttributes.SDN_ENABLE)) {
        SdnAgent agent = getOwner().sensors().get(SdnAgent.SDN_AGENT);
        if (agent == null) {
          throw new IllegalStateException("SDN agent entity on " + getOwner() + " is null");
        }
        Map<String, Cidr> networks =
            agent.sensors().get(SdnAgent.SDN_PROVIDER).sensors().get(SdnProvider.SUBNETS);
        entity.config().set(SubnetTier.SUBNET_CIDR, networks.get(entity.getApplicationId()));
      } else {
        entity.config().set(SubnetTier.SUBNET_CIDR, Cidr.UNIVERSAL);
      }
      configureEnrichers(entity);

      // Add the entity Dockerfile if configured
      String dockerfile = entity.config().get(DockerAttributes.DOCKERFILE_URL);
      String entrypoint = entity.config().get(DockerAttributes.DOCKERFILE_ENTRYPOINT_URL);
      String contextArchive = entity.config().get(DockerAttributes.DOCKERFILE_CONTEXT_URL);
      String imageId = entity.config().get(DockerAttributes.DOCKER_IMAGE_ID);

      Optional<String> baseImage =
          Optional.fromNullable(entity.config().get(DockerAttributes.DOCKER_IMAGE_NAME));
      String imageTag =
          Optional.fromNullable(entity.config().get(DockerAttributes.DOCKER_IMAGE_TAG))
              .or("latest");

      // TODO incorporate more info
      final String imageName = DockerUtils.imageName(entity, dockerfile);

      // Lookup image ID or build new image from Dockerfile
      LOG.info("ImageName for entity {}: {}", entity, imageName);

      if (dockerHost.getImageNamed(imageName, imageTag).isPresent()) {
        // Wait until committed before continuing - Brooklyn may be midway through its creation.
        waitForImage(imageName);

        // Look up imageId again
        imageId = dockerHost.getImageNamed(imageName, imageTag).get();
        LOG.info("Found image {} for entity: {}", imageName, imageId);

        // Skip install phase
        entity.config().set(SoftwareProcess.SKIP_INSTALLATION, true);
      } else if (baseImage.isPresent()) {
        if (useSsh) {
          // Create an SSHable image from the one configured
          imageId = dockerHost.layerSshableImageOn(baseImage.get(), imageTag);
          LOG.info("Created SSHable image from {}: {}", baseImage.get(), imageId);
        } else {
          dockerHost.runDockerCommand(String.format("pull %s:%s", baseImage.get(), imageTag));
          imageId = dockerHost.getImageNamed(baseImage.get(), imageTag).get();
        }
        entity.config().set(SoftwareProcess.SKIP_INSTALLATION, true);
      } else {
        // Otherwise Clocker is going to make an image for the entity once it is installed.
        insertCallback(entity, SoftwareProcess.POST_INSTALL_COMMAND, DockerCallbacks.commit());

        if (Strings.isNonBlank(dockerfile)) {
          if (imageId != null) {
            LOG.warn(
                "Ignoring container imageId {} as dockerfile URL is set: {}", imageId, dockerfile);
          }
          Map<String, Object> substitutions = getExtraTemplateSubstitutions(imageName, entity);
          imageId =
              dockerHost.buildImage(
                  dockerfile, entrypoint, contextArchive, imageName, useSsh, substitutions);
        }
        if (Strings.isBlank(imageId)) {
          imageId = getOwner().sensors().get(DockerHost.DOCKER_IMAGE_ID);
        }

        // Tag the image name and create its latch
        images.putIfAbsent(imageName, new CountDownLatch(1));
        dockerHost.runDockerCommand(String.format("tag -f %s %s:latest", imageId, imageName));
      }

      // Look up hardware ID
      String hardwareId = entity.config().get(DockerAttributes.DOCKER_HARDWARE_ID);
      if (Strings.isEmpty(hardwareId)) {
        hardwareId = getOwner().config().get(DockerAttributes.DOCKER_HARDWARE_ID);
      }

      // Create new Docker container in the host cluster
      LOG.info(
          "Starting container with imageId {} and hardwareId {} at {}",
          new Object[] {imageId, hardwareId, machine});
      Map<Object, Object> containerFlags =
          MutableMap.builder()
              .putAll(flags)
              .put("useSsh", useSsh)
              .put("entity", entity)
              .putIfNotNull("imageId", imageId)
              .putIfNotNull("hardwareId", hardwareId)
              .build();
      DynamicCluster cluster = dockerHost.getDockerContainerCluster();
      Entity added = cluster.addNode(machine, containerFlags);
      if (added == null) {
        throw new NoMachinesAvailableException(
            String.format("Failed to create container at %s", dockerHost.getDockerHostName()));
      } else {
        Entities.invokeEffector(
                (EntityLocal) entity,
                added,
                Startable.START,
                MutableMap.of("locations", ImmutableList.of(machine)))
            .getUnchecked();
      }
      DockerContainer dockerContainer = (DockerContainer) added;

      // Save the container attributes
      dockerContainer.sensors().set(DockerContainer.IMAGE_ID, imageId);
      dockerContainer.sensors().set(DockerContainer.IMAGE_NAME, imageName);
      dockerContainer.sensors().set(DockerContainer.HARDWARE_ID, hardwareId);

      // record SDN application network details
      if (getOwner().config().get(SdnAttributes.SDN_ENABLE)) {
        SdnAgent agent = getOwner().sensors().get(SdnAgent.SDN_AGENT);
        Cidr applicationCidr =
            agent.sensors().get(SdnAgent.SDN_PROVIDER).getSubnetCidr(entity.getApplicationId());
        entity.sensors().set(SdnProvider.APPLICATION_CIDR, applicationCidr);
        dockerContainer.sensors().set(SdnProvider.APPLICATION_CIDR, applicationCidr);
      }

      return dockerContainer.getDynamicLocation();
    } finally {
      lock.readLock().unlock();
    }
  }
Example #27
0
  public List<String> scanSlaves(JsonArray slaves) throws UnknownHostException {
    List<String> slaveIds = MutableList.<String>of();
    for (int i = 0; i < slaves.size(); i++) {
      JsonObject slave = slaves.get(i).getAsJsonObject();
      boolean active = slave.get("active").getAsBoolean();
      String id = slave.get("id").getAsString();
      String hostname = slave.get("hostname").getAsString();
      Double registered = slave.get("registered_time").getAsDouble();
      Group group = sensors().get(MESOS_SLAVES);

      Optional<Entity> entity =
          Iterables.tryFind(
              group.getMembers(),
              Predicates.compose(
                  Predicates.equalTo(id), EntityFunctions.attribute(MesosSlave.MESOS_SLAVE_ID)));
      if (entity.isPresent()) {
        Entity found = entity.get();
        found.sensors().set(MesosSlave.SLAVE_ACTIVE, active);
        if (!active) {
          Lifecycle state = found.sensors().get(Attributes.SERVICE_STATE_ACTUAL);
          if (Lifecycle.ON_FIRE.equals(state) || Lifecycle.STARTING.equals(state)) {
            continue;
          } else if (Lifecycle.STOPPING.equals(state) || Lifecycle.STOPPED.equals(state)) {
            group.removeMember(found);
            group.removeChild(found);
            Entities.unmanage(found);
          } else {
            ServiceStateLogic.setExpectedState(found, Lifecycle.STOPPING);
          }
        }
      } else if (active) {
        LocationSpec<SshMachineLocation> spec =
            LocationSpec.create(SshMachineLocation.class)
                .configure(SshMachineLocation.SSH_HOST, hostname)
                .configure("address", InetAddress.getByName(hostname))
                .displayName(hostname);
        if (config().get(MESOS_SLAVE_ACCESSIBLE)) {
          spec.configure(CloudLocationConfig.WAIT_FOR_SSHABLE, "true")
              .configure(SshMachineLocation.DETECT_MACHINE_DETAILS, true)
              .configure(SshMachineLocation.SSH_PORT, config().get(MesosSlave.SLAVE_SSH_PORT))
              .configure(LocationConfigKeys.USER, config().get(MesosSlave.SLAVE_SSH_USER))
              .configure(LocationConfigKeys.PASSWORD, config().get(MesosSlave.SLAVE_SSH_PASSWORD))
              .configure(SshTool.PROP_PASSWORD, config().get(MesosSlave.SLAVE_SSH_PASSWORD))
              .configure(SshTool.PROP_PORT, config().get(MesosSlave.SLAVE_SSH_PORT))
              .configure(
                  LocationConfigKeys.PRIVATE_KEY_DATA,
                  config().get(MesosSlave.SLAVE_SSH_PRIVATE_KEY_DATA))
              .configure(
                  LocationConfigKeys.PRIVATE_KEY_FILE,
                  config().get(MesosSlave.SLAVE_SSH_PRIVATE_KEY_FILE));
        } else {
          spec.configure(CloudLocationConfig.WAIT_FOR_SSHABLE, "false")
              .configure(SshMachineLocation.DETECT_MACHINE_DETAILS, false);
        }
        SshMachineLocation machine =
            getManagementContext().getLocationManager().createLocation(spec);

        // Setup port forwarding
        MarathonPortForwarder portForwarder = new MarathonPortForwarder();
        portForwarder.setManagementContext(getManagementContext());

        EntitySpec<MesosSlave> slaveSpec =
            EntitySpec.create(MesosSlave.class)
                .configure(MesosSlave.MESOS_SLAVE_ID, id)
                .configure(MesosSlave.REGISTERED_AT, registered.longValue())
                .configure(MesosSlave.MESOS_CLUSTER, this)
                .displayName("Mesos Slave (" + hostname + ")");
        MesosSlave added = sensors().get(MESOS_SLAVES).addMemberChild(slaveSpec);
        added.sensors().set(MesosSlave.SLAVE_ACTIVE, active);
        added.sensors().set(MesosSlave.HOSTNAME, hostname);
        added.sensors().set(MesosSlave.ADDRESS, hostname);

        added.start(ImmutableList.of(machine));
        portForwarder.init(hostname, this);

        // Setup subnet tier
        SubnetTier subnetTier =
            added.addChild(
                EntitySpec.create(SubnetTier.class)
                    .configure(SubnetTier.PORT_FORWARDER, portForwarder)
                    .configure(SubnetTier.SUBNET_CIDR, Cidr.UNIVERSAL));
        Entities.start(subnetTier, ImmutableList.of(machine));
        added.sensors().set(MesosSlave.SUBNET_TIER, subnetTier);
      }

      if (active) slaveIds.add(id);
    }
    return slaveIds;
  }
Example #28
0
 @Override
 public void waitForEntityStart() {
   Entities.waitForServiceUp(this);
 }
    @SuppressWarnings({"rawtypes", "unchecked"})
    @Override
    public V call() {
      T value = source.getAttribute(sensor);

      // return immediately if either the ready predicate or the abort conditions hold
      if (ready(value)) return postProcess(value);

      final List<Exception> abortionExceptions = Lists.newCopyOnWriteArrayList();
      long start = System.currentTimeMillis();

      for (AttributeAndSensorCondition abortCondition : abortSensorConditions) {
        Object abortValue = abortCondition.source.getAttribute(abortCondition.sensor);
        if (abortCondition.predicate.apply(abortValue)) {
          abortionExceptions.add(
              new Exception(
                  "Abort due to " + abortCondition.source + " -> " + abortCondition.sensor));
        }
      }
      if (abortionExceptions.size() > 0) {
        throw new CompoundRuntimeException(
            "Aborted waiting for ready from " + source + " " + sensor, abortionExceptions);
      }

      TaskInternal<?> current = (TaskInternal<?>) Tasks.current();
      if (current == null)
        throw new IllegalStateException("Should only be invoked in a running task");
      Entity entity = BrooklynTaskTags.getTargetOrContextEntity(current);
      if (entity == null)
        throw new IllegalStateException(
            "Should only be invoked in a running task with an entity tag; "
                + current
                + " has no entity tag ("
                + current.getStatusDetail(false)
                + ")");

      final LinkedList<T> publishedValues = new LinkedList<T>();
      final Semaphore semaphore = new Semaphore(0); // could use Exchanger
      SubscriptionHandle subscription = null;
      List<SubscriptionHandle> abortSubscriptions = Lists.newArrayList();

      try {
        subscription =
            entity
                .subscriptions()
                .subscribe(
                    source,
                    sensor,
                    new SensorEventListener<T>() {
                      @Override
                      public void onEvent(SensorEvent<T> event) {
                        synchronized (publishedValues) {
                          publishedValues.add(event.getValue());
                        }
                        semaphore.release();
                      }
                    });
        for (final AttributeAndSensorCondition abortCondition : abortSensorConditions) {
          abortSubscriptions.add(
              entity
                  .subscriptions()
                  .subscribe(
                      abortCondition.source,
                      abortCondition.sensor,
                      new SensorEventListener<Object>() {
                        @Override
                        public void onEvent(SensorEvent<Object> event) {
                          if (abortCondition.predicate.apply(event.getValue())) {
                            abortionExceptions.add(
                                new Exception(
                                    "Abort due to "
                                        + abortCondition.source
                                        + " -> "
                                        + abortCondition.sensor));
                            semaphore.release();
                          }
                        }
                      }));
          Object abortValue = abortCondition.source.getAttribute(abortCondition.sensor);
          if (abortCondition.predicate.apply(abortValue)) {
            abortionExceptions.add(
                new Exception(
                    "Abort due to " + abortCondition.source + " -> " + abortCondition.sensor));
          }
        }
        if (abortionExceptions.size() > 0) {
          throw new CompoundRuntimeException(
              "Aborted waiting for ready from " + source + " " + sensor, abortionExceptions);
        }

        CountdownTimer timer = timeout != null ? timeout.countdownTimer() : null;
        Duration maxPeriod = ValueResolver.PRETTY_QUICK_WAIT;
        Duration nextPeriod = ValueResolver.REAL_QUICK_PERIOD;
        while (true) {
          // check the source on initial run (could be done outside the loop)
          // and also (optionally) on each iteration in case it is more recent
          value = source.getAttribute(sensor);
          if (ready(value)) break;

          if (timer != null) {
            if (timer.getDurationRemaining().isShorterThan(nextPeriod)) {
              nextPeriod = timer.getDurationRemaining();
            }
            if (timer.isExpired()) {
              if (onTimeout.isPresent()) return onTimeout.get();
              throw new RuntimeTimeoutException("Unsatisfied after " + Duration.sinceUtc(start));
            }
          }

          String prevBlockingDetails = current.setBlockingDetails(blockingDetails);
          try {
            if (semaphore.tryAcquire(nextPeriod.toMilliseconds(), TimeUnit.MILLISECONDS)) {
              // immediately release so we are available for the next check
              semaphore.release();
              // if other permits have been made available (e.g. multiple notifications) drain them
              // all as no point running multiple times
              semaphore.drainPermits();
            }
          } finally {
            current.setBlockingDetails(prevBlockingDetails);
          }

          // check any subscribed values which have come in first
          while (true) {
            synchronized (publishedValues) {
              if (publishedValues.isEmpty()) break;
              value = publishedValues.pop();
            }
            if (ready(value)) break;
          }

          // if unmanaged then ignore the other abort conditions
          if (!ignoreUnmanaged && Entities.isNoLongerManaged(entity)) {
            if (onUnmanaged.isPresent()) return onUnmanaged.get();
            throw new NotManagedException(entity);
          }

          if (abortionExceptions.size() > 0) {
            throw new CompoundRuntimeException(
                "Aborted waiting for ready from " + source + " " + sensor, abortionExceptions);
          }

          nextPeriod = nextPeriod.times(2).upperBound(maxPeriod);
        }
        if (LOG.isDebugEnabled()) LOG.debug("Attribute-ready for {} in entity {}", sensor, source);
        return postProcess(value);
      } catch (InterruptedException e) {
        throw Exceptions.propagate(e);
      } finally {
        if (subscription != null) {
          entity.subscriptions().unsubscribe(subscription);
        }
        for (SubscriptionHandle handle : abortSubscriptions) {
          entity.subscriptions().unsubscribe(handle);
        }
      }
    }