protected void registerEtcHosts(
      SshMachineLocation machine, String ip, Iterable<String> hostnames) {
    log.info("Updating /etc/hosts of " + machine + ": adding " + ip + " = " + hostnames);

    checkArgument(
        Strings.isNonBlank(ip) && Networking.isValidIp4(ip), "invalid IPv4 address %s", ip);
    if (Strings.isBlank(ip) || Iterables.isEmpty(hostnames)) return;
    String line = ip + " " + Joiner.on(" ").join(hostnames);
    exec(machine, true, "echo " + line + " >> /etc/hosts");
  }
 // TODO Suggest that other entities follow this pattern as well: check for port availability early
 // to report failures early, and in case getShellEnvironment() tries to convert any null port
 // numbers
 // to int.
 @Override
 public void prepare() {
   super.prepare();
   Networking.checkPortsValid(getPortMap());
 }
  @SuppressWarnings("deprecation")
  @Override
  public void launch() {
    String app = getEntity().getAttribute(BrooklynNode.APP);
    String locations = getEntity().getAttribute(BrooklynNode.LOCATIONS);
    boolean hasLocalBrooklynProperties =
        getEntity().getConfig(BrooklynNode.BROOKLYN_LOCAL_PROPERTIES_CONTENTS) != null
            || getEntity().getConfig(BrooklynNode.BROOKLYN_LOCAL_PROPERTIES_URI) != null;
    String localBrooklynPropertiesPath =
        processTemplateContents(
            getEntity().getConfig(BrooklynNode.BROOKLYN_LOCAL_PROPERTIES_REMOTE_PATH));
    InetAddress bindAddress = getEntity().getAttribute(BrooklynNode.WEB_CONSOLE_BIND_ADDRESS);
    InetAddress publicAddress = getEntity().getAttribute(BrooklynNode.WEB_CONSOLE_PUBLIC_ADDRESS);

    String cmd = entity.getConfig(BrooklynNode.LAUNCH_COMMAND);
    if (Strings.isBlank(cmd)) cmd = "./bin/brooklyn";
    cmd = "nohup " + cmd + " launch";
    if (app != null) {
      cmd += " --app " + app;
    }
    if (locations != null) {
      cmd += " --locations " + locations;
    }
    if (entity.getConfig(BrooklynNode.ON_EXISTING_PROPERTIES_FILE)
        == ExistingFileBehaviour.DO_NOT_USE) {
      cmd += " --noGlobalBrooklynProperties";
    }
    if (hasLocalBrooklynProperties) {
      cmd += " --localBrooklynProperties " + localBrooklynPropertiesPath;
    }
    Integer webPort = null;
    if (getEntity().isHttpProtocolEnabled("http")) {
      webPort = getEntity().getAttribute(BrooklynNode.HTTP_PORT);
      Networking.checkPortsValid(ImmutableMap.of("webPort", webPort));
    } else if (getEntity().isHttpProtocolEnabled("https")) {
      webPort = getEntity().getAttribute(BrooklynNode.HTTPS_PORT);
      Networking.checkPortsValid(ImmutableMap.of("webPort", webPort));
    }
    if (webPort != null) {
      cmd += " --port " + webPort;
    } else if (getEntity().getEnabledHttpProtocols().isEmpty()) {
      // TODO sensors will probably not work in this mode
      cmd += " --noConsole";
    } else {
      throw new IllegalStateException(
          "Unknown web protocol in "
              + BrooklynNode.ENABLED_HTTP_PROTOCOLS
              + " "
              + "("
              + getEntity().getEnabledHttpProtocols()
              + "); expecting 'http' or 'https'");
    }

    if (bindAddress != null) {
      cmd += " --bindAddress " + bindAddress.getHostAddress();
    }
    if (publicAddress != null) {
      cmd += " --publicAddress " + publicAddress.getHostName();
    }
    if (getEntity().getAttribute(BrooklynNode.NO_WEB_CONSOLE_AUTHENTICATION)) {
      cmd += " --noConsoleSecurity";
    }
    if (Strings.isNonBlank(getEntity().getConfig(BrooklynNode.EXTRA_LAUNCH_PARAMETERS))) {
      cmd += " " + getEntity().getConfig(BrooklynNode.EXTRA_LAUNCH_PARAMETERS);
    }
    cmd += format(" >> %s/console 2>&1 </dev/null &", getRunDir());

    log.info("Starting brooklyn on {} using command {}", getMachine(), cmd);

    // relies on brooklyn script creating pid file
    newScript(
            ImmutableMap.of(
                "usePidFile",
                entity.getConfig(BrooklynNode.LAUNCH_COMMAND_CREATES_PID_FILE)
                    ? false
                    : getPidFile()),
            LAUNCHING)
        .body
        .append(
            format("export BROOKLYN_CLASSPATH=%s", getRunDir() + "/lib/\"*\""),
            format("export BROOKLYN_HOME=%s", getBrooklynHome()),
            format(cmd))
        .failOnNonZeroResultCode()
        .execute();
  }