public static SshEffectorTaskFactory<Integer> ssh(List<String> commands) { return ssh(commands.toArray(new String[commands.size()])); }
public static TaskFactory<?> buildChefFile(String runDirectory, String chefDirectory, String phase, Iterable<? extends String> runList, Map<String, Object> optionalAttributes) { // TODO if it's server, try knife first // TODO configure add'l properties String phaseRb = "root = " + "'"+runDirectory+"'" // recommended alternate to runDir is the following, but it is not available in some rubies //+ File.absolute_path(File.dirname(__FILE__))"+ + "\n"+ "file_cache_path root\n"+ // "cookbook_path root + '/cookbooks'\n"; "cookbook_path '"+chefDirectory+"'\n"; Map<String,Object> phaseJsonMap = MutableMap.of(); if (optionalAttributes!=null) phaseJsonMap.putAll(optionalAttributes); if (runList!=null) phaseJsonMap.put("run_list", ImmutableList.copyOf(runList)); Gson json = new GsonBuilder().create(); String phaseJson = json.toJson(phaseJsonMap); return Tasks.sequential("build chef files for "+phase, SshEffectorTasks.put(Urls.mergePaths(runDirectory)+"/"+phase+".rb").contents(phaseRb).createDirectory(), SshEffectorTasks.put(Urls.mergePaths(runDirectory)+"/"+phase+".json").contents(phaseJson)); }
protected boolean tryCheckStartPid() { if (getPidFile()==null) return false; // if it's still up after 5s assume we are good (default behaviour) Time.sleep(Duration.FIVE_SECONDS); if (!DynamicTasks.queue(SshEffectorTasks.isPidFromFileRunning(getPidFile()).runAsRoot()).get()) { throw new IllegalStateException("The process for "+entity()+" appears not to be running (pid file "+getPidFile()+")"); } // and set the PID entity().sensors().set(Attributes.PID, Integer.parseInt(DynamicTasks.queue(SshEffectorTasks.ssh("cat "+getPidFile()).runAsRoot()).block().getStdout().trim())); return true; }
@Test(groups="Integration") public void testRunningPidFromFile() throws IOException { File f = File.createTempFile("testBrooklynPid", ".pid"); Files.write( (""+getMyPid()).getBytes(), f ); ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.codePidFromFileRunning(f.getPath())); Assert.assertEquals(t.getTask().getUnchecked(), (Integer)0); ProcessTaskWrapper<Boolean> t2 = submit(SshEffectorTasks.isPidFromFileRunning(f.getPath())); Assert.assertTrue(t2.getTask().getUnchecked()); }
@Override public void customizeService() { DynamicTasks.queue( SshEffectorTasks.put("/tmp/" + getServiceScriptFileName()) .contents(TemplateProcessor.processTemplateContents( ResourceUtils.create().getResourceAsString(config().get(CustomService.SERVICE_SCRIPT_TEMPLATE_URL)), this, ImmutableMap.<String,String>of())), SshEffectorTasks.put("/tmp/" + getMetaInfoXmlFileName()) .contents(TemplateProcessor.processTemplateContents( ResourceUtils.create().getResourceAsString(config().get(CustomService.SERVICE_METAINFO_TEMPLATE_URL)), this, ImmutableMap.<String,String>of())), SshEffectorTasks.ssh( sudo(format("mkdir -p %s", getServiceDirectory())), sudo(format("mv /tmp/%s %s", getMetaInfoXmlFileName(), getServiceDirectory())), sudo(format("mkdir -p %s", getServiceScriptDirectory())), sudo(format("mv /tmp/%s %s/",getServiceScriptFileName(), getServiceScriptDirectory())), sudo(format("mkdir -p %s", getServiceConfigDirectory())))); Map<String, ?> serviceConf = getConfig(CustomService.CUSTOM_SERVICE_CONF); for (Entry<String, ?> entry: serviceConf.entrySet()) { DynamicTasks.queue( SshEffectorTasks.put("/tmp/" + getServicePropertyFileName(entry.getKey())) .contents(prepareServiceConfigurationXmlContent(entry.getKey(), (Map) entry.getValue())), SshEffectorTasks.ssh( sudo(format("mv %s %s/", "/tmp/" + getServicePropertyFileName(entry.getKey()), getServiceConfigDirectory())))); } DynamicTasks.waitForLast(); }
protected boolean tryStopPid() { Integer pid = entity().getAttribute(Attributes.PID); if (pid==null) { if (entity().getAttribute(Attributes.SERVICE_STATE_ACTUAL)==Lifecycle.RUNNING && getPidFile()==null) log.warn("No PID recorded for "+entity()+" when running, with PID file "+getPidFile()+"; skipping kill in "+Tasks.current()); else if (log.isDebugEnabled()) log.debug("No PID recorded for "+entity()+"; skipping ("+entity().getAttribute(Attributes.SERVICE_STATE_ACTUAL)+" / "+getPidFile()+")"); return false; } // allow non-zero exit as process may have already been killed DynamicTasks.queue(SshEffectorTasks.ssh( "kill "+pid, "sleep 5", BashCommands.ok("kill -9 "+pid)).allowingNonZeroExitCode().runAsRoot()).block(); if (DynamicTasks.queue(SshEffectorTasks.isPidRunning(pid).runAsRoot()).get()) { throw new IllegalStateException("Process for "+entity()+" in "+pid+" still running after kill"); } entity().sensors().set(Attributes.PID, null); return true; }
@Test(groups="Integration") public void testNonRunningPid() { ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.codePidRunning(99999)); Assert.assertNotEquals(t.getTask().getUnchecked(), 0); Assert.assertNotEquals(t.getExitCode(), 0); ProcessTaskWrapper<Boolean> t2 = submit(SshEffectorTasks.isPidRunning(99999)); Assert.assertFalse(t2.getTask().getUnchecked()); }
protected void checkIsRunningAndStops(Entity mysql, SshMachineLocation lh) { Integer pid = getPid(mysql); Assert.assertNotNull(pid, "PID should be set as an attribute (or getPid() overridden to supply)"); Entities.submit(app, SshEffectorTasks.requirePidRunning(pid).machine(lh).newTask() ).get(); app.stop(); // let the kill -1 take effect Time.sleep(Duration.ONE_SECOND); // and assert it has died log.info("mysql in pid "+pid+" should be dead now"); // (app has stopped, so submit on mgmt context) ProcessTaskWrapper<Integer> t = SshEffectorTasks.codePidRunning(pid).machine(lh).newTask(); mgmt.getExecutionManager().submit(t); Assert.assertNotEquals(t.block().getExitCode(), 0); } }
/** task which fails if the given PID is not running */ public static SshEffectorTaskFactory<?> requirePidRunning(Integer pid) { return codePidRunning(pid).summary("PID "+pid+" is-running check (required)").requiringExitCodeZero("Process with PID "+pid+" is required to be running"); }
/** as {@link #codePidFromFileRunning(String)} but returning boolean */ public static SshEffectorTaskFactory<Boolean> isPidFromFileRunning(String pidFile) { return codePidFromFileRunning(pidFile).summary("PID file "+pidFile+" is-running check (boolean)"). returning(new Function<ProcessTaskWrapper<?>, Boolean>() { @Override public Boolean apply(@Nullable ProcessTaskWrapper<?> input) { return ((Integer)0).equals(input.getExitCode()); } }); }
@Override protected String startProcessesAtMachine(Supplier<MachineLocation> machineS) { DynamicTasks.queue( SshEffectorTasks.ssh( "mkdir "+dir(entity), "cd "+dir(entity), BashCommands.downloadToStdout(downloadUrl(entity, isLocalhost(machineS)))+" | tar xvz" ).summary("download mysql").returning(SshTasks.returningStdoutLoggingInfo(log, true))); if (isLinux(machineS)) { DynamicTasks.queue(SshEffectorTasks.ssh(BashCommands.installPackage("libaio1"))); } DynamicTasks.queue( SshEffectorTasks.put(".my.cnf") .contents(String.format("[mysqld]\nbasedir=%s/%s\n", dir(entity), installDir(entity, isLocalhost(machineS)))), SshEffectorTasks.ssh( "cd "+dir(entity)+"/*", "./scripts/mysql_install_db", "./support-files/mysql.server start > out.log 2> err.log < /dev/null" ).summary("setup and run mysql").returning(SshTasks.returningStdoutLoggingInfo(log, true))); return "submitted start"; } @Override
protected boolean tryStopPid() { Integer pid = entity().getAttribute(Attributes.PID); if (pid==null) { if (entity().getAttribute(Attributes.SERVICE_STATE_ACTUAL)==Lifecycle.RUNNING && getPidFile()==null) log.warn("No PID recorded for "+entity()+" when running, with PID file "+getPidFile()+"; skipping kill in "+Tasks.current()); else if (log.isDebugEnabled()) log.debug("No PID recorded for "+entity()+"; skipping ("+entity().getAttribute(Attributes.SERVICE_STATE_ACTUAL)+" / "+getPidFile()+")"); return false; } // allow non-zero exit as process may have already been killed DynamicTasks.queue(SshEffectorTasks.ssh( "kill "+pid, "sleep 5", BashCommands.ok("kill -9 "+pid)).allowingNonZeroExitCode().runAsRoot()).block(); if (DynamicTasks.queue(SshEffectorTasks.isPidRunning(pid).runAsRoot()).get()) { throw new IllegalStateException("Process for "+entity()+" in "+pid+" still running after kill"); } entity().sensors().set(Attributes.PID, null); return true; }
@Test(groups="Integration") public void testRunningPid() { ProcessTaskWrapper<Integer> t = submit(SshEffectorTasks.codePidRunning(getMyPid())); Assert.assertEquals(t.getTask().getUnchecked(), (Integer)0); ProcessTaskWrapper<Boolean> t2 = submit(SshEffectorTasks.isPidRunning(getMyPid())); Assert.assertTrue(t2.getTask().getUnchecked()); }
/** as {@link #codePidRunning(Integer)} but returning boolean */ public static SshEffectorTaskFactory<Boolean> isPidRunning(Integer pid) { return codePidRunning(pid).summary("PID "+pid+" is-running check (boolean)").returning(new Function<ProcessTaskWrapper<?>, Boolean>() { @Override public Boolean apply(@Nullable ProcessTaskWrapper<?> input) { return Integer.valueOf(0).equals(input.getExitCode()); } }); }
/** task which fails if the pid in the given file is not running (or if there is no such PID file); * method accepts wildcards so long as they match a single file on the remote end (fails if 0 or 2+ matching files) */ public static SshEffectorTaskFactory<?> requirePidFromFileRunning(String pidFile) { return codePidFromFileRunning(pidFile) .summary("PID file "+pidFile+" is-running check (required)") .requiringExitCodeZero("Process with PID from file "+pidFile+" is required to be running"); }
/** task which returns 0 if pid is running */ public static SshEffectorTaskFactory<Integer> codePidRunning(Integer pid) { return ssh("ps -p "+pid).summary("PID "+pid+" is-running check (exit code)").allowingNonZeroExitCode(); }
@Override public void customize() { DynamicTasks.queue(SshEffectorTasks.ssh(sudoAsUser("postgres", "/etc/init.d/postgresql stop")).allowingNonZeroExitCode()).get(); DynamicTasks.queue(SshEffectorTasks.ssh( executeCommandThenAsUserTeeOutputToFile( chainGroup( String contents = processTemplate(configUrl); DynamicTasks.queue( SshEffectorTasks.put("/tmp/postgresql.conf").contents(contents), SshEffectorTasks.ssh(sudoAsUser("postgres", "cp /tmp/postgresql.conf " + getDataDir() + "/postgresql.conf"))); DynamicTasks.queue(SshEffectorTasks.ssh( String contents = processTemplate(authConfigUrl); DynamicTasks.queue( SshEffectorTasks.put("/tmp/pg_hba.conf").contents(contents), SshEffectorTasks.ssh(sudoAsUser("postgres", "cp /tmp/pg_hba.conf " + getDataDir() + "/pg_hba.conf")));
protected boolean tryCheckStartPid() { if (getPidFile()==null) return false; // if it's still up after 5s assume we are good (default behaviour) Time.sleep(Duration.FIVE_SECONDS); if (!DynamicTasks.queue(SshEffectorTasks.isPidFromFileRunning(getPidFile()).runAsRoot()).get()) { throw new IllegalStateException("The process for "+entity()+" appears not to be running (pid file "+getPidFile()+")"); } // and set the PID entity().sensors().set(Attributes.PID, Integer.parseInt(DynamicTasks.queue(SshEffectorTasks.ssh("cat "+getPidFile()).runAsRoot()).block().getStdout().trim())); return true; }
public static TaskFactory<?> buildChefFile(String runDirectory, String chefDirectory, String phase, Iterable<? extends String> runList, Map<String, Object> optionalAttributes) { // TODO if it's server, try knife first // TODO configure add'l properties String phaseRb = "root = " + "'"+runDirectory+"'" // recommended alternate to runDir is the following, but it is not available in some rubies //+ File.absolute_path(File.dirname(__FILE__))"+ + "\n"+ "file_cache_path root\n"+ // "cookbook_path root + '/cookbooks'\n"; "cookbook_path '"+chefDirectory+"'\n"; Map<String,Object> phaseJsonMap = MutableMap.of(); if (optionalAttributes!=null) phaseJsonMap.putAll(optionalAttributes); if (runList!=null) phaseJsonMap.put("run_list", ImmutableList.copyOf(runList)); Gson json = new GsonBuilder().create(); String phaseJson = json.toJson(phaseJsonMap); return Tasks.sequential("build chef files for "+phase, SshEffectorTasks.put(Urls.mergePaths(runDirectory)+"/"+phase+".rb").contents(phaseRb).createDirectory(), SshEffectorTasks.put(Urls.mergePaths(runDirectory)+"/"+phase+".json").contents(phaseJson)); }
public static TaskFactory<?> installChef(String chefDirectory, boolean force) { // TODO check on entity whether it is chef _server_ String installCmd = cdAndRun(chefDirectory, ChefBashCommands.INSTALL_FROM_OPSCODE); if (!force) installCmd = BashCommands.alternatives("which chef-solo", installCmd); return SshEffectorTasks.ssh(installCmd).summary("install chef"); }