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"); } }
@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(); }