protected void appendTemplate(String template, String destination, SshMachineLocation machine) {
   String content = ((BindDnsServerSshDriver) getDriver()).processTemplate(template);
   String temp = "/tmp/template-" + Strings.makeRandomId(6);
   machine.copyTo(new ByteArrayInputStream(content.getBytes()), temp);
   machine.execScript(
       "updating file",
       ImmutableList.of(
           BashCommands.sudo(String.format("tee -a %s < %s", destination, temp)),
           String.format("rm -f %s", temp)));
 }
  @Override
  public void init() {
    super.init();

    ConfigToAttributes.apply(this, DOCKER_HOST);
    ConfigToAttributes.apply(this, DOCKER_REGISTRY_PORT);

    DockerHost host = (DockerHost) sensors().get(DOCKER_HOST);
    String installDir = host.sensors().get(SoftwareProcess.INSTALL_DIR);
    SshMachineLocation sshMachine = host.getDynamicLocation().getMachine();
    String sshMachineInstallDir = getSSHMachineInstallDir();

    config()
        .set(
            DockerAttributes.DOCKER_PORT_BINDINGS,
            MutableMap.of(sensors().get(DOCKER_REGISTRY_PORT), 5000));
    config()
        .set(
            DockerAttributes.DOCKER_HOST_VOLUME_MAPPING,
            MutableMap.of(Os.mergePaths(installDir, "certs"), "/certs"));

    sshMachine.installTo(
        ImmutableMap.of(SshTool.PROP_PERMISSIONS.getName(), "0755"),
        SCRIPT_LOCATION,
        Os.mergePaths(sshMachineInstallDir, CREATE_CERTS_SCRIPT_NAME));
    sshMachine.installTo(
        config().get(DockerInfrastructure.DOCKER_CA_CERTIFICATE_PATH),
        Os.mergePaths(sshMachineInstallDir, "ca-cert.pem"));
    sshMachine.installTo(
        config().get(DockerInfrastructure.DOCKER_CA_KEY_PATH),
        Os.mergePaths(sshMachineInstallDir, "ca-key.pem"));

    int result =
        sshMachine.execCommands(
            "installCerts",
            ImmutableList.of(
                BashCommands.sudo(
                    String.format(
                        "%s %s %s",
                        Os.mergePaths(sshMachineInstallDir, CREATE_CERTS_SCRIPT_NAME),
                        host.sensors().get(Attributes.ADDRESS),
                        sshMachineInstallDir))));
    if (result != 0) {
      throw new IllegalStateException("Could not create certificates for docker registry");
    }
  }
Example #3
0
 @Override
 public void close() throws IOException {
   LOG.info("Close called on Docker host {}: {}", machine, this);
   try {
     machine.close();
   } catch (Exception e) {
     LOG.info("{}: Closing Docker host: {}", e.getMessage(), this);
     throw Exceptions.propagate(e);
   } finally {
     LOG.info("Docker host closed: {}", this);
   }
 }
  private void uploadFileContents(String contents, String alternativeUri, String remotePath) {
    checkNotNull(remotePath, "remotePath");
    SshMachineLocation machine = getMachine();
    String tempRemotePath = String.format("%s/upload.tmp", getRunDir());

    if (contents == null && alternativeUri == null) {
      throw new IllegalStateException("No contents supplied for file " + remotePath);
    }
    InputStream stream =
        contents != null
            ? new ByteArrayInputStream(contents.getBytes())
            : resource.getResourceFromUrl(alternativeUri);
    Map<String, String> flags = MutableMap.of(SshTool.PROP_PERMISSIONS.getName(), "0600");
    machine.copyTo(flags, stream, tempRemotePath);
    newScript(CUSTOMIZING)
        .failOnNonZeroResultCode()
        .body
        .append(
            format("mkdir -p %s", remotePath.subSequence(0, remotePath.lastIndexOf("/"))),
            format("cp -p %s %s", tempRemotePath, remotePath),
            format("rm -f %s", tempRemotePath))
        .execute();
  }
  /**
   * Resolves the on-box dir.
   *
   * <p>Initialize and pre-create the right onbox working dir, if an ssh machine location. Logs a
   * warning if not.
   */
  @SuppressWarnings("deprecation")
  public static String resolveOnBoxDir(EntityInternal entity, MachineLocation machine) {
    String base = entity.getConfig(BrooklynConfigKeys.ONBOX_BASE_DIR);
    if (base == null) base = machine.getConfig(BrooklynConfigKeys.ONBOX_BASE_DIR);
    if (base != null && Boolean.TRUE.equals(entity.getConfig(ON_BOX_BASE_DIR_RESOLVED)))
      return base;
    if (base == null)
      base = entity.getManagementContext().getConfig().getConfig(BrooklynConfigKeys.ONBOX_BASE_DIR);
    if (base == null) base = entity.getConfig(BrooklynConfigKeys.BROOKLYN_DATA_DIR);
    if (base == null) base = machine.getConfig(BrooklynConfigKeys.BROOKLYN_DATA_DIR);
    if (base == null)
      base =
          entity.getManagementContext().getConfig().getConfig(BrooklynConfigKeys.BROOKLYN_DATA_DIR);
    if (base == null) base = "~/brooklyn-managed-processes";
    if (base.equals("~")) base = ".";
    if (base.startsWith("~/")) base = "." + base.substring(1);

    String resolvedBase = null;
    if (entity.getConfig(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION)
        || machine.getConfig(BrooklynConfigKeys.SKIP_ON_BOX_BASE_DIR_RESOLUTION)) {
      if (log.isDebugEnabled())
        log.debug("Skipping on-box base dir resolution for " + entity + " at " + machine);
      if (!Os.isAbsolutish(base)) base = "~/" + base;
      resolvedBase = Os.tidyPath(base);
    } else if (machine instanceof SshMachineLocation) {
      SshMachineLocation ms = (SshMachineLocation) machine;
      ProcessTaskWrapper<Integer> baseTask =
          SshEffectorTasks.ssh(
                  BashCommands.alternatives(
                      "mkdir -p \"${BASE_DIR}\"",
                      BashCommands.chain(
                          BashCommands.sudo("mkdir -p \"${BASE_DIR}\""),
                          BashCommands.sudo("chown " + ms.getUser() + " \"${BASE_DIR}\""))),
                  "cd ~",
                  "cd ${BASE_DIR}",
                  "echo BASE_DIR_RESULT':'`pwd`:BASE_DIR_RESULT")
              .environmentVariable("BASE_DIR", base)
              .requiringExitCodeZero()
              .summary("initializing on-box base dir " + base)
              .newTask();
      DynamicTasks.queueIfPossible(baseTask).orSubmitAsync(entity);
      resolvedBase =
          Strings.getFragmentBetween(
              baseTask.block().getStdout(), "BASE_DIR_RESULT:", ":BASE_DIR_RESULT");
    }
    if (resolvedBase == null) {
      if (!Os.isAbsolutish(base)) base = "~/" + base;
      resolvedBase = Os.tidyPath(base);
      log.warn(
          "Could not resolve on-box directory for "
              + entity
              + " at "
              + machine
              + "; using "
              + resolvedBase
              + ", though this may not be accurate at the target (and may fail shortly)");
    }
    entity.config().set(BrooklynConfigKeys.ONBOX_BASE_DIR, resolvedBase);
    entity.config().set(ON_BOX_BASE_DIR_RESOLVED, true);
    return resolvedBase;
  }
    public void run() {
      log.info("Starting {} on machine {}", entity(), machine);
      Collection<Location> oldLocs = entity().getLocations();
      if (!oldLocs.isEmpty()) {
        List<MachineLocation> oldSshLocs =
            ImmutableList.copyOf(Iterables.filter(oldLocs, MachineLocation.class));
        if (!oldSshLocs.isEmpty()) {
          // check if existing locations are compatible
          log.debug(
              "Entity "
                  + entity()
                  + " had machine locations "
                  + oldSshLocs
                  + " when starting at "
                  + machine
                  + "; checking if they are compatible");
          for (MachineLocation oldLoc : oldSshLocs) {
            // machines are deemed compatible if hostname and address are the same, or they are
            // localhost
            // this allows a machine create by jclouds to then be defined with an ip-based spec
            if (!"localhost".equals(machine.getConfig(AbstractLocation.ORIGINAL_SPEC))) {
              checkLocationParametersCompatible(
                  machine,
                  oldLoc,
                  "hostname",
                  oldLoc.getAddress().getHostName(),
                  machine.getAddress().getHostName());
              checkLocationParametersCompatible(
                  machine,
                  oldLoc,
                  "address",
                  oldLoc.getAddress().getHostAddress(),
                  machine.getAddress().getHostAddress());
            }
          }
          log.debug(
              "Entity "
                  + entity()
                  + " old machine locations "
                  + oldSshLocs
                  + " were compatible, removing them to start at "
                  + machine);
          entity().removeLocations(oldSshLocs);
        }
      }
      entity().addLocations(ImmutableList.of((Location) machine));

      // elsewhere we rely on (public) hostname being set _after_ subnet_hostname
      // (to prevent the tiny possibility of races resulting in hostname being returned
      // simply because subnet is still being looked up)
      Maybe<String> lh = Machines.getSubnetHostname(machine);
      Maybe<String> la = Machines.getSubnetIp(machine);
      if (lh.isPresent()) entity().sensors().set(Attributes.SUBNET_HOSTNAME, lh.get());
      if (la.isPresent()) entity().sensors().set(Attributes.SUBNET_ADDRESS, la.get());
      entity().sensors().set(Attributes.HOSTNAME, machine.getAddress().getHostName());
      entity().sensors().set(Attributes.ADDRESS, machine.getAddress().getHostAddress());
      if (machine instanceof SshMachineLocation) {
        SshMachineLocation sshMachine = (SshMachineLocation) machine;
        UserAndHostAndPort sshAddress =
            UserAndHostAndPort.fromParts(
                sshMachine.getUser(), sshMachine.getAddress().getHostName(), sshMachine.getPort());
        // FIXME: Who or what is SSH_ADDRESS intended for? It's not necessarily the address that
        // the SshMachineLocation is using for ssh connections (because it accepts SSH_HOST as an
        // override).
        entity().sensors().set(Attributes.SSH_ADDRESS, sshAddress);
      }

      if (Boolean.TRUE.equals(entity().getConfig(SoftwareProcess.OPEN_IPTABLES))) {
        if (machine instanceof SshMachineLocation) {
          @SuppressWarnings("unchecked")
          Iterable<Integer> inboundPorts =
              (Iterable<Integer>) machine.config().get(CloudLocationConfig.INBOUND_PORTS);
          machineInitTasks.openIptablesAsync(inboundPorts, (SshMachineLocation) machine);
        } else {
          log.warn("Ignoring flag OPEN_IPTABLES on non-ssh location {}", machine);
        }
      }
      if (Boolean.TRUE.equals(entity().getConfig(SoftwareProcess.STOP_IPTABLES))) {
        if (machine instanceof SshMachineLocation) {
          machineInitTasks.stopIptablesAsync((SshMachineLocation) machine);
        } else {
          log.warn("Ignoring flag STOP_IPTABLES on non-ssh location {}", machine);
        }
      }
      if (Boolean.TRUE.equals(entity().getConfig(SoftwareProcess.DONT_REQUIRE_TTY_FOR_SUDO))) {
        if (machine instanceof SshMachineLocation) {
          machineInitTasks.dontRequireTtyForSudoAsync((SshMachineLocation) machine);
        } else {
          log.warn("Ignoring flag DONT_REQUIRE_TTY_FOR_SUDO on non-ssh location {}", machine);
        }
      }
      resolveOnBoxDir(entity(), machine);
      preStartCustom(machine);
    }
 protected void assertSshable(SshMachineLocation machine) {
   int result = machine.execScript("simplecommand", ImmutableList.of("true"));
   assertEquals(result, 0);
 }
  @Override
  public void customize() {
    newScript(CUSTOMIZING)
        .failOnNonZeroResultCode()
        .body
        .append(
            // workaround for AMP distribution placing everything in the root of this archive, but
            // brooklyn distribution placing everything in a subdirectory: check to see if
            // subdirectory
            // with expected name exists; symlink to same directory if it doesn't
            // FIXME remove when all downstream usages don't use this
            format("[ -d %1$s ] || ln -s . %1$s", getExpandedInstallDir(), getExpandedInstallDir()),

            // previously we only copied bin,conf and set BROOKLYN_HOME to the install dir;
            // but that does not play nicely if installing dists other than brooklyn
            // (such as what is built by our artifact)
            format("cp -R %s/* .", getExpandedInstallDir()),
            "mkdir -p ./lib/dropins/")
        .execute();

    SshMachineLocation machine = getMachine();
    BrooklynNode entity = getEntity();

    String brooklynGlobalPropertiesRemotePath =
        entity.getConfig(BrooklynNode.BROOKLYN_GLOBAL_PROPERTIES_REMOTE_PATH);
    String brooklynGlobalPropertiesContents =
        entity.getConfig(BrooklynNode.BROOKLYN_GLOBAL_PROPERTIES_CONTENTS);
    String brooklynGlobalPropertiesUri =
        entity.getConfig(BrooklynNode.BROOKLYN_GLOBAL_PROPERTIES_URI);

    String brooklynLocalPropertiesRemotePath =
        processTemplateContents(
            entity.getConfig(BrooklynNode.BROOKLYN_LOCAL_PROPERTIES_REMOTE_PATH));
    String brooklynLocalPropertiesContents =
        entity.getConfig(BrooklynNode.BROOKLYN_LOCAL_PROPERTIES_CONTENTS);
    String brooklynLocalPropertiesUri =
        entity.getConfig(BrooklynNode.BROOKLYN_LOCAL_PROPERTIES_URI);

    String brooklynCatalogRemotePath = entity.getConfig(BrooklynNode.BROOKLYN_CATALOG_REMOTE_PATH);
    String brooklynCatalogContents = entity.getConfig(BrooklynNode.BROOKLYN_CATALOG_CONTENTS);
    String brooklynCatalogUri = entity.getConfig(BrooklynNode.BROOKLYN_CATALOG_URI);

    // Override the ~/.brooklyn/brooklyn.properties if required
    if (brooklynGlobalPropertiesContents != null || brooklynGlobalPropertiesUri != null) {
      ExistingFileBehaviour onExisting = entity.getConfig(BrooklynNode.ON_EXISTING_PROPERTIES_FILE);
      Integer checkExists =
          DynamicTasks.queue(
                  SshEffectorTasks.ssh("ls \"" + brooklynGlobalPropertiesRemotePath + "\"")
                      .allowingNonZeroExitCode())
              .get();
      boolean doUpload = true;
      if (checkExists == 0) {
        switch (onExisting) {
          case USE_EXISTING:
            doUpload = false;
            break;
          case OVERWRITE:
            break;
          case DO_NOT_USE:
            throw new IllegalStateException(
                "Properties file "
                    + brooklynGlobalPropertiesContents
                    + " already exists and "
                    + "even though it is not being used, content for it was supplied");
          case FAIL:
            throw new IllegalStateException(
                "Properties file "
                    + brooklynGlobalPropertiesContents
                    + " already exists and "
                    + BrooklynNode.ON_EXISTING_PROPERTIES_FILE
                    + " response is to fail");
          default:
            throw new IllegalStateException(
                "Properties file "
                    + brooklynGlobalPropertiesContents
                    + " already exists and "
                    + BrooklynNode.ON_EXISTING_PROPERTIES_FILE
                    + " response "
                    + onExisting
                    + " is unknown");
        }
      }
      if (onExisting == ExistingFileBehaviour.DO_NOT_USE) {
        log.warn(
            "Global properties supplied when told not to use them; no global properties exists, so it will be installed, but it will not be used.");
      }
      if (doUpload)
        uploadFileContents(
            brooklynGlobalPropertiesContents,
            brooklynGlobalPropertiesUri,
            brooklynGlobalPropertiesRemotePath);
    }

    // Upload a local-brooklyn.properties if required
    if (brooklynLocalPropertiesContents != null || brooklynLocalPropertiesUri != null) {
      uploadFileContents(
          brooklynLocalPropertiesContents,
          brooklynLocalPropertiesUri,
          brooklynLocalPropertiesRemotePath);
    }

    // Override the ~/.brooklyn/catalog.xml if required
    if (brooklynCatalogContents != null || brooklynCatalogUri != null) {
      uploadFileContents(brooklynCatalogContents, brooklynCatalogUri, brooklynCatalogRemotePath);
    }

    // Copy additional resources to the server
    for (Map.Entry<String, String> entry :
        getEntity().getAttribute(BrooklynNode.COPY_TO_RUNDIR).entrySet()) {
      Map<String, String> substitutions = ImmutableMap.of("RUN", getRunDir());
      String localResource = entry.getKey();
      String remotePath = entry.getValue();
      String resolvedRemotePath = remotePath;
      for (Map.Entry<String, String> substitution : substitutions.entrySet()) {
        String key = substitution.getKey();
        String val = substitution.getValue();
        resolvedRemotePath =
            resolvedRemotePath.replace("${" + key + "}", val).replace("$" + key, val);
      }
      machine.copyTo(
          MutableMap.of("permissions", "0600"),
          resource.getResourceFromUrl(localResource),
          resolvedRemotePath);
    }

    for (Object entry : getEntity().getClasspath()) {
      String filename = null;
      String url = null;

      if (entry instanceof String) {
        url = (String) entry;
      } else {
        if (entry instanceof Map) {
          url = (String) ((Map) entry).get("url");
          filename = (String) ((Map) entry).get("filename");
        }
      }
      checkNotNull(url, "url");

      // If a local folder, then create archive from contents first
      if (Urls.isDirectory(url)) {
        File jarFile = ArchiveBuilder.jar().addDirContentsAt(new File(url), "").create();
        url = jarFile.getAbsolutePath();
      }

      if (filename == null) {
        // Determine filename
        filename = getFilename(url);
      }
      ArchiveUtils.deploy(
          MutableMap.<String, Object>of(),
          url,
          machine,
          getRunDir(),
          Os.mergePaths(getRunDir(), "lib", "dropins"),
          filename);
    }

    String cmd = entity.getConfig(BrooklynNode.EXTRA_CUSTOMIZATION_SCRIPT);
    if (Strings.isNonBlank(cmd)) {
      DynamicTasks.queueIfPossible(
              SshEffectorTasks.ssh(cmd)
                  .summary("Bespoke BrooklynNode customization script")
                  .requiringExitCodeZero())
          .orSubmitAndBlock(getEntity());
    }
  }
 @Override
 public void init() {
   super.init();
 }