/** * deploys a bundle * * @param input bundle distribution ZIP file * @param group to be deployed to (a BundleDestination is created on top of given group), group * must be compatible and it's resources must support bundle deployment * @param config input configuration for bundle (for passing input-parameter values) * @param destinationName - name for new destination being created * @param baseDirName - baseDir for deployment - this must match to resourceType contained in * given group * @param deployDir - directory to deploy to - relative path based on baseDir * @return bundleDeployment where deployment has finished (either failed or success) * @throws Exception */ public BundleDeployment deployBundle( File input, ResourceGroup group, Configuration config, String destinationName, String baseDirName, String deployDir) throws Exception { BundleVersion version = createBundleVersion(input); BundleDestination destination = bundleManager.createBundleDestination( client.getSubject(), version.getBundle().getId(), destinationName, "", baseDirName, deployDir, group.getId()); BundleDeployment deployment = bundleManager.createBundleDeployment( client.getSubject(), version.getId(), destination.getId(), "", config); deployment = bundleManager.scheduleBundleDeployment(client.getSubject(), deployment.getId(), false); return waitForBundleDeployment(deployment); }
/** * waits until given BundleDeployment is not in PENDING or IN_PROGRESS state, then returns * BundleDeployment instance, which is going to be either SUCCESS or FAILURE * * @param deployment * @return */ private BundleDeployment waitForBundleDeployment(BundleDeployment deployment) { while (deployment.getStatus().equals(BundleDeploymentStatus.IN_PROGRESS) || deployment.getStatus().equals(BundleDeploymentStatus.PENDING)) { try { Thread.currentThread().join(3 * 1000); } catch (InterruptedException e) { e.printStackTrace(); } BundleDeploymentCriteria criteria = new BundleDeploymentCriteria(); criteria.addFilterId(deployment.getId()); deployment = bundleManager.findBundleDeploymentsByCriteria(client.getSubject(), criteria).get(0); } return deployment; }
@Override public void execute(JobExecutionContext context) throws JobExecutionException { BundleManagerLocal bundleManager = LookupUtil.getBundleManager(); SubjectManagerLocal subjectManager = LookupUtil.getSubjectManager(); Subject overlord = subjectManager.getOverlord(); PageList<BundleDeployment> deployments = bundleManager.findBundleDeploymentsByCriteria(overlord, getCriteriaFromContext(context)); if (deployments.size() > 0) { BundleDeployment bundleDeployment = deployments.get(0); SchedulerLocal scheduler = LookupUtil.getSchedulerBean(); JobDetail jobDetail = context.getJobDetail(); BundleDeploymentStatus bundleDeploymentStatus = bundleManager.determineBundleDeploymentStatus(bundleDeployment.getId()); if (bundleDeploymentStatus.isTerminal()) { // delete this job, we've assigned a final status try { context.setResult(bundleDeploymentStatus); // Return status to possible listeners scheduler.deleteJob(jobDetail.getName(), jobDetail.getGroup()); } catch (SchedulerException e) { throw new JobExecutionException( "Could not delete the bundle deployment completion check job for " + bundleDeployment + ".", e); } } else { // try again in 10s try { Trigger trigger = QuartzUtil.getFireOnceOffsetTrigger(jobDetail, 10000L); // just need a trigger name unique for this job trigger.setName(String.valueOf(System.currentTimeMillis())); scheduler.scheduleJob(trigger); } catch (SchedulerException e) { throw new JobExecutionException( "Could not schedule the bundle deployment completion check job for " + bundleDeployment + ".", e); } } } }
public ControlResults invoke(String operation, Configuration params) { ControlResults results = new ControlResults(); try { Bundle bundle = getBundle(); BundleVersion bundleVersion = getBundleVersion(bundle); Configuration bundleConfig = new Configuration(); File clusterDir = new File(params.getSimpleValue("clusterDirectory")); int numNodes = Integer.parseInt(params.getSimpleValue("numberOfNodes")); int replicationFactor = Integer.parseInt(params.getSimpleValue("replicationFactor", "1")); String hostname = params.getSimpleValue("host"); Resource platform = getPlatform(hostname); ResourceGroup group = getPlatformGroup(platform, hostname); Set<String> ipAddresses = calculateLocalIPAddresses(numNodes); for (int i = 0; i < numNodes; ++i) { Set<String> seeds = getSeeds(ipAddresses, i + 1); int jmxPort = 7200 + i; Configuration deploymentConfig = new Configuration(); deploymentConfig.put(new PropertySimple("cluster.name", "rhqdev")); deploymentConfig.put(new PropertySimple("cluster.dir", clusterDir.getAbsolutePath())); deploymentConfig.put(new PropertySimple("auto.bootstrap", "false")); deploymentConfig.put(new PropertySimple("data.dir", "data")); deploymentConfig.put(new PropertySimple("commitlog.dir", "commit_log")); deploymentConfig.put(new PropertySimple("log.dir", "logs")); deploymentConfig.put(new PropertySimple("saved.caches.dir", "saved_caches")); deploymentConfig.put(new PropertySimple("hostname", getLocalIPAddress(i + 1))); deploymentConfig.put(new PropertySimple("seeds", collectionToString(seeds))); deploymentConfig.put(new PropertySimple("jmx.port", Integer.toString(jmxPort))); deploymentConfig.put(new PropertySimple("initial.token", generateToken(i, numNodes))); deploymentConfig.put(new PropertySimple("install.schema", i == 0)); deploymentConfig.put(new PropertySimple("replication.factor", replicationFactor)); String destinationName = "cassandra-node[" + i + "]-deployment"; String deployDir = new File(clusterDir, "node" + i).getAbsolutePath(); BundleDestination bundleDestination = getBundleDestination(bundleVersion, destinationName, group, deployDir); BundleDeployment bundleDeployment = bundleManager.createBundleDeployment( overlord, bundleVersion.getId(), bundleDestination.getId(), destinationName, deploymentConfig); bundleManager.scheduleBundleDeployment(overlord, bundleDeployment.getId(), true); } return new ControlResults(); } catch (ResourceNotFoundException e) { results.setError(e.getMessage()); return results; } catch (Exception e) { results.setError(e); return results; } }
private void upgrade(boolean clean) throws Exception { testAntBundleInitialInstall(); // install a bundle first cleanPluginDirs(); // clean everything but the dest dir - we want to upgrade the destination prepareBeforeTestMethod(); // prepare for our new test // deploy upgrade and test it ResourceType resourceType = new ResourceType("testSimpleBundle2Type", "plugin", ResourceCategory.SERVER, null); BundleType bundleType = new BundleType("testSimpleBundle2BType", resourceType); Repo repo = new Repo("test-bundle-two"); PackageType packageType = new PackageType("test-bundle-two", resourceType); Bundle bundle = new Bundle("test-bundle-two", bundleType, repo, packageType); BundleVersion bundleVersion = new BundleVersion( "test-bundle-two", "3.0", bundle, getRecipeFromFile("test-bundle-three.xml")); BundleDestination destination = new BundleDestination( bundle, "testSimpleBundle2Dest", new ResourceGroup("testSimpleBundle2Group"), DEST_BASE_DIR_NAME, this.destDir.getAbsolutePath()); Configuration config = new Configuration(); String customPropName = "custom.prop"; String customPropValue = "DEF"; String onePropName = "one.prop"; String onePropValue = "one-one-one"; String threePropName = "three.prop"; String threePropValue = "333"; config.put(new PropertySimple(customPropName, customPropValue)); config.put(new PropertySimple(onePropName, onePropValue)); config.put(new PropertySimple(threePropName, threePropValue)); BundleDeployment deployment = new BundleDeployment(); deployment.setId(456); deployment.setName("test bundle 3 deployment name - upgrades test bundle 2"); deployment.setBundleVersion(bundleVersion); deployment.setConfiguration(config); deployment.setDestination(destination); // copy the test archive file to the bundle files dir FileUtil.copyFile( new File("src/test/resources/test-bundle-three-archive.zip"), new File(this.bundleFilesDir, "test-bundle-three-archive.zip")); // create test.properties file in the bundle files dir File file1 = new File(this.bundleFilesDir, "test.properties"); Properties props = new Properties(); props.setProperty(customPropName, "@@" + customPropName + "@@"); FileOutputStream outputStream = new FileOutputStream(file1); props.store(outputStream, "test.properties comment"); outputStream.close(); // create some additional files - note: recipe says to ignore "ignore/**" File ignoreDir = new File(this.destDir, "ignore"); File extraDir = new File(this.destDir, "extra"); ignoreDir.mkdirs(); extraDir.mkdirs(); File ignoredFile = new File(ignoreDir, "ignore-file.txt"); File extraFile = new File(extraDir, "extra-file.txt"); FileUtil.writeFile(new ByteArrayInputStream("ignore".getBytes()), ignoredFile); FileUtil.writeFile(new ByteArrayInputStream("extra".getBytes()), extraFile); BundleDeployRequest request = new BundleDeployRequest(); request.setBundleFilesLocation(this.bundleFilesDir); request.setResourceDeployment(new BundleResourceDeployment(deployment, null)); request.setBundleManagerProvider(new MockBundleManagerProvider()); request.setAbsoluteDestinationDirectory(this.destDir); request.setCleanDeployment(clean); BundleDeployResult results = plugin.deployBundle(request); assertResultsSuccess(results); // test that the prop was replaced in raw file test.properties Properties realizedProps = new Properties(); loadProperties( realizedProps, new FileInputStream(new File(this.destDir, "config/test.properties"))); assert customPropValue.equals(realizedProps.getProperty(customPropName)) : "didn't replace prop"; // test that the archive was extracted properly. These are the files in the archive or removed // from original: // REMOVED: zero-file.txt // one/one-file.txt (content: "@@one.prop@@") <-- recipe says this is to be replaced // two/two-file.txt (content: "@@two.prop@@") <-- recipe does not say to replace this // three/three-file.txt (content: "@@three.prop@@") <-- recipe says this is to be replaced File zeroFile = new File(this.destDir, "zero-file.txt"); File oneFile = new File(this.destDir, "one/one-file.txt"); File twoFile = new File(this.destDir, "two/two-file.txt"); File threeFile = new File(this.destDir, "three/three-file.txt"); assert !zeroFile.exists() : "zero file should have been removed during upgrade"; assert oneFile.exists() : "one file missing"; assert twoFile.exists() : "two file missing"; assert threeFile.exists() : "three file missing"; if (clean) { assert !ignoredFile.exists() : "ignored file should have been deleted due to clean deployment request"; assert !extraFile.exists() : "extra file should have been deleted due to clean deployment request"; } else { assert ignoredFile.exists() : "ignored file wasn't ignored, it was deleted"; assert !extraFile.exists() : "extra file ignored, but it should have been deleted/backed up"; } assert readFile(oneFile).startsWith(onePropValue); assert readFile(twoFile).startsWith("@@two.prop@@"); assert readFile(threeFile).startsWith(threePropValue); DeploymentsMetadata metadata = new DeploymentsMetadata(this.destDir); DeploymentProperties deploymentProps = metadata.getDeploymentProperties(deployment.getId()); assert deploymentProps.getDeploymentId() == deployment.getId(); assert deploymentProps.getBundleName().equals(bundle.getName()); assert deploymentProps.getBundleVersion().equals(bundleVersion.getVersion()); assert deploymentProps.getManageRootDir() == true; DeploymentProperties currentProps = metadata.getCurrentDeploymentProperties(); assert deploymentProps.equals(currentProps); // check the backup directory - note, clean flag is irrelevent when determining what should be // backed up File backupDir = metadata.getDeploymentBackupDirectory(deployment.getId()); File extraBackupFile = new File(backupDir, extraDir.getName() + File.separatorChar + extraFile.getName()); File ignoredBackupFile = new File(backupDir, ignoreDir.getName() + File.separatorChar + ignoredFile.getName()); assert !ignoredBackupFile.exists() : "ignored file was backed up but it should not have been"; assert extraBackupFile.exists() : "extra file was not backed up"; assert "extra".equals(new String(StreamUtil.slurp(new FileInputStream(extraBackupFile)))) : "bad backup of extra"; DeploymentProperties previousProps = metadata.getPreviousDeploymentProperties(456); assert previousProps != null : "There should be previous deployment metadata"; assert previousProps.getDeploymentId() == 123 : "bad previous deployment metadata"; // testAntBundleInitialInstall used 123 assert previousProps.getBundleName().equals(deploymentProps.getBundleName()); assert previousProps .getBundleVersion() .equals("2.5"); // testAntBundleInitialInstall deployed version 2.5 assert previousProps.getManageRootDir() == true; }
/** * Test deployment of an RHQ bundle recipe where the deploy directory is not to be fully managed. */ @Test(enabled = true) public void testAntBundleNoManageRootDir() throws Exception { ResourceType resourceType = new ResourceType("testNoManageRootDirBundle", "plugin", ResourceCategory.SERVER, null); BundleType bundleType = new BundleType("testNoManageRootDirBundle", resourceType); Repo repo = new Repo("testNoManageRootDirBundle"); PackageType packageType = new PackageType("testNoManageRootDirBundle", resourceType); Bundle bundle = new Bundle("testNoManageRootDirBundle", bundleType, repo, packageType); BundleVersion bundleVersion = new BundleVersion( "testNoManageRootDirBundle", "1.0", bundle, getRecipeFromFile("test-bundle-no-manage-root-dir.xml")); BundleDestination destination = new BundleDestination( bundle, "testNoManageRootDirBundle", new ResourceGroup("testNoManageRootDirBundle"), DEST_BASE_DIR_NAME, this.destDir.getAbsolutePath()); Configuration config = new Configuration(); BundleDeployment deployment = new BundleDeployment(); deployment.setName("test bundle deployment name"); deployment.setBundleVersion(bundleVersion); deployment.setConfiguration(config); deployment.setDestination(destination); // create bundle test files File file0 = new File(this.bundleFilesDir, "zero.properties"); Properties props = new Properties(); props.setProperty("zero", "0"); FileOutputStream outputStream = new FileOutputStream(file0); props.store(outputStream, "zero file"); outputStream.close(); File file1 = new File(this.bundleFilesDir, "one.properties"); props.clear(); props.setProperty("one", "1"); outputStream = new FileOutputStream(file1); props.store(outputStream, "one file"); outputStream.close(); File file2 = new File(this.bundleFilesDir, "two.properties"); props.clear(); props.setProperty("two", "2"); outputStream = new FileOutputStream(file2); props.store(outputStream, "two file"); outputStream.close(); // create some external test files that don't belong to the bundle but are in the dest dir // (which is not fully managed by the bundle) this.destDir.mkdirs(); File external1 = new File(this.destDir, "external1.properties"); props.clear(); props.setProperty("external1", "1"); outputStream = new FileOutputStream(external1); props.store(outputStream, "external1 file"); outputStream.close(); File external2 = new File(this.destDir, "extdir/external2.properties"); external2.getParentFile().mkdirs(); props.clear(); props.setProperty("external2", "2"); outputStream = new FileOutputStream(external2); props.store(outputStream, "external2 file"); outputStream.close(); // deploy the bundle BundleDeployRequest request = new BundleDeployRequest(); request.setBundleFilesLocation(this.bundleFilesDir); request.setResourceDeployment(new BundleResourceDeployment(deployment, null)); request.setBundleManagerProvider(new MockBundleManagerProvider()); request.setAbsoluteDestinationDirectory(this.destDir); BundleDeployResult results = plugin.deployBundle(request); assertResultsSuccess(results); // test that files were deployed in the proper place props.clear(); loadProperties(props, new FileInputStream(new File(this.destDir, "zero.properties"))); assert "0".equals(props.getProperty("zero")) : "did not deploy bundle correctly 0"; loadProperties(props, new FileInputStream(new File(this.destDir, "subdir1/one.properties"))); assert "1".equals(props.getProperty("one")) : "did not deploy bundle correctly 1"; loadProperties(props, new FileInputStream(new File(this.destDir, "subdir2/two.properties"))); assert "2".equals(props.getProperty("two")) : "did not deploy bundle correctly 2"; DeploymentsMetadata metadata = new DeploymentsMetadata(this.destDir); assert metadata.isManaged() == true : "missing metadata directory"; assert metadata.getCurrentDeploymentProperties().getManageRootDir() == false : "should not be managing root dir"; // make sure our unmanaged files/directories weren't removed props.clear(); loadProperties(props, new FileInputStream(new File(this.destDir, "external1.properties"))); assert "1".equals(props.getProperty("external1")) : "bundle deployment removed our unmanaged file 1"; loadProperties( props, new FileInputStream(new File(this.destDir, "extdir/external2.properties"))); assert "2".equals(props.getProperty("external2")) : "bundle deployment removed our unmanaged file 2"; // now purge the bundle - this should only purge those files that were laid down by the bundle // plus the metadata directory BundlePurgeRequest purgeRequest = new BundlePurgeRequest(); purgeRequest.setLiveResourceDeployment(new BundleResourceDeployment(deployment, null)); purgeRequest.setBundleManagerProvider(new MockBundleManagerProvider()); purgeRequest.setAbsoluteDestinationDirectory(this.destDir); BundlePurgeResult purgeResults = plugin.purgeBundle(purgeRequest); assertResultsSuccess(purgeResults); // make sure our bundle files have been completely purged; the metadata directory should have // been purged too assert new File(this.destDir, "zero.properties").exists() == false; assert new File(this.destDir, "subdir1/one.properties").exists() == false; assert new File(this.destDir, "subdir2/two.properties").exists() == false; assert new File(this.destDir, "subdir1").exists() == false; assert new File(this.destDir, "subdir2").exists() == false; assert this.destDir.exists() == true : "deploy dir should still exist, we were told not to fully manage it"; metadata = new DeploymentsMetadata(this.destDir); assert metadata.getMetadataDirectory().exists() == false : "metadata directory should not exist"; // make sure our external, unmanaged files still exist - the purge should not have deleted these props.clear(); loadProperties(props, new FileInputStream(new File(this.destDir, "external1.properties"))); assert "1".equals(props.getProperty("external1")) : "bundle purge removed our unmanaged file 1"; loadProperties( props, new FileInputStream(new File(this.destDir, "extdir/external2.properties"))); assert "2".equals(props.getProperty("external2")) : "bundle purge removed our unmanaged file 2"; }
/** Test deployment of an RHQ bundle recipe. */ @Test(enabled = true) public void testAntBundle() throws Exception { ResourceType resourceType = new ResourceType("testSimpleBundle", "plugin", ResourceCategory.SERVER, null); BundleType bundleType = new BundleType("testSimpleBundle", resourceType); Repo repo = new Repo("testSimpleBundle"); PackageType packageType = new PackageType("testSimpleBundle", resourceType); Bundle bundle = new Bundle("testSimpleBundle", bundleType, repo, packageType); BundleVersion bundleVersion = new BundleVersion("testSimpleBundle", "1.0", bundle, getRecipeFromFile("test-bundle.xml")); BundleDestination destination = new BundleDestination( bundle, "testSimpleBundle", new ResourceGroup("testSimpleBundle"), DEST_BASE_DIR_NAME, this.destDir.getAbsolutePath()); Configuration config = new Configuration(); String realPropValue = "ABC123"; config.put(new PropertySimple("custom.prop1", realPropValue)); BundleDeployment deployment = new BundleDeployment(); deployment.setName("test bundle deployment name"); deployment.setBundleVersion(bundleVersion); deployment.setConfiguration(config); deployment.setDestination(destination); // create test file File file1 = new File(this.bundleFilesDir, "test.properties"); Properties props = new Properties(); props.setProperty("custom.prop1", "@@custom.prop1@@"); FileOutputStream outputStream = new FileOutputStream(file1); props.store(outputStream, "replace"); outputStream.close(); // create noreplace test file File noreplacefile = new File(this.bundleFilesDir, "noreplace.properties"); outputStream = new FileOutputStream(noreplacefile); props.store(outputStream, "noreplace"); outputStream.close(); // create foo test file File foofile = new File(this.bundleFilesDir, "foo.properties"); outputStream = new FileOutputStream(foofile); props.store(outputStream, "foo"); outputStream.close(); BundleDeployRequest request = new BundleDeployRequest(); request.setBundleFilesLocation(this.bundleFilesDir); request.setResourceDeployment(new BundleResourceDeployment(deployment, null)); request.setBundleManagerProvider(new MockBundleManagerProvider()); request.setAbsoluteDestinationDirectory(this.destDir); BundleDeployResult results = plugin.deployBundle(request); assertResultsSuccess(results); // test that the prop was replaced in test.properties Properties realizedProps = new Properties(); loadProperties( realizedProps, new FileInputStream(new File(this.destDir, "config/test.properties"))); assert realPropValue.equals(realizedProps.getProperty("custom.prop1")) : "didn't replace prop"; // test that the prop was not replaced in noreplace.properties Properties notrealizedProps = new Properties(); loadProperties( notrealizedProps, new FileInputStream(new File(this.destDir, "config/noreplace.properties"))); assert "@@custom.prop1@@".equals(notrealizedProps.getProperty("custom.prop1")) : "replaced prop when it shouldn't"; }
/** Test deployment of an RHQ bundle recipe with archive file and raw file */ @Test(enabled = true) public void testAntBundleInitialInstall() throws Exception { ResourceType resourceType = new ResourceType("testSimpleBundle2Type", "plugin", ResourceCategory.SERVER, null); BundleType bundleType = new BundleType("testSimpleBundle2BType", resourceType); Repo repo = new Repo("test-bundle-two"); PackageType packageType = new PackageType("test-bundle-two", resourceType); Bundle bundle = new Bundle("test-bundle-two", bundleType, repo, packageType); BundleVersion bundleVersion = new BundleVersion( "test-bundle-two", "2.5", bundle, getRecipeFromFile("test-bundle-two.xml")); BundleDestination destination = new BundleDestination( bundle, "testSimpleBundle2Dest", new ResourceGroup("testSimpleBundle2Group"), DEST_BASE_DIR_NAME, this.destDir.getAbsolutePath()); Configuration config = new Configuration(); String customPropName = "custom.prop"; String customPropValue = "ABC"; String onePropName = "one.prop"; String onePropValue = "111"; config.put(new PropertySimple(customPropName, customPropValue)); config.put(new PropertySimple(onePropName, onePropValue)); BundleDeployment deployment = new BundleDeployment(); deployment.setId(123); deployment.setName("test bundle 2 deployment name"); deployment.setBundleVersion(bundleVersion); deployment.setConfiguration(config); deployment.setDestination(destination); // copy the test archive file to the bundle files dir FileUtil.copyFile( new File("src/test/resources/test-bundle-two-archive.zip"), new File(this.bundleFilesDir, "test-bundle-two-archive.zip")); // create test.properties file in the bundle files dir File file1 = new File(this.bundleFilesDir, "test.properties"); Properties props = new Properties(); props.setProperty(customPropName, "@@" + customPropName + "@@"); FileOutputStream outputStream = new FileOutputStream(file1); props.store(outputStream, "test.properties comment"); outputStream.close(); BundleDeployRequest request = new BundleDeployRequest(); request.setBundleFilesLocation(this.bundleFilesDir); request.setResourceDeployment(new BundleResourceDeployment(deployment, null)); request.setBundleManagerProvider(new MockBundleManagerProvider()); request.setAbsoluteDestinationDirectory(this.destDir); BundleDeployResult results = plugin.deployBundle(request); assertResultsSuccess(results); // test that the prop was replaced in raw file test.properties Properties realizedProps = new Properties(); loadProperties( realizedProps, new FileInputStream(new File(this.destDir, "config/test.properties"))); assert customPropValue.equals(realizedProps.getProperty(customPropName)) : "didn't replace prop"; // test that the archive was extracted properly. These are the files in the archive: // zero-file.txt (content: "zero") // one/one-file.txt (content: "@@one.prop@@") <-- recipe says this is to be replaced // two/two-file.txt (content: "@@two.prop@@") <-- recipe does not say to replace this File zeroFile = new File(this.destDir, "zero-file.txt"); File oneFile = new File(this.destDir, "one/one-file.txt"); File twoFile = new File(this.destDir, "two/two-file.txt"); assert zeroFile.exists() : "zero file missing"; assert oneFile.exists() : "one file missing"; assert twoFile.exists() : "two file missing"; assert readFile(zeroFile).startsWith("zero"); assert readFile(oneFile).startsWith(onePropValue); assert readFile(twoFile).startsWith("@@two.prop@@"); DeploymentsMetadata metadata = new DeploymentsMetadata(this.destDir); DeploymentProperties deploymentProps = metadata.getDeploymentProperties(deployment.getId()); assert deploymentProps.getDeploymentId() == deployment.getId(); assert deploymentProps.getBundleName().equals(bundle.getName()); assert deploymentProps.getBundleVersion().equals(bundleVersion.getVersion()); assert deploymentProps.getManageRootDir() == true; DeploymentProperties currentProps = metadata.getCurrentDeploymentProperties(); assert deploymentProps.equals(currentProps); DeploymentProperties previousProps = metadata.getPreviousDeploymentProperties(deployment.getId()); assert previousProps == null : "There should not be any previous deployment metadata"; }
@Test(enabled = true) public void testAntBundleRevert() throws Exception { // install then upgrade a bundle first testAntBundleUpgrade(); cleanPluginDirs(); // clean everything but the dest dir - we want to keep the metadata prepareBeforeTestMethod(); // prepare for our new test // we installed version 2.5 then upgraded to 3.0 // now we want to revert back to 2.5 ResourceType resourceType = new ResourceType("testSimpleBundle2Type", "plugin", ResourceCategory.SERVER, null); BundleType bundleType = new BundleType("testSimpleBundle2BType", resourceType); Repo repo = new Repo("test-bundle-two"); PackageType packageType = new PackageType("test-bundle-two", resourceType); Bundle bundle = new Bundle("test-bundle-two", bundleType, repo, packageType); BundleVersion bundleVersion = new BundleVersion( "test-bundle-two", "2.5", bundle, getRecipeFromFile("test-bundle-two.xml")); BundleDestination destination = new BundleDestination( bundle, "testSimpleBundle2Dest", new ResourceGroup("testSimpleBundle2Group"), DEST_BASE_DIR_NAME, this.destDir.getAbsolutePath()); Configuration config = new Configuration(); String customPropName = "custom.prop"; String customPropValue = "ABC-revert"; String onePropName = "one.prop"; String onePropValue = "111-revert"; config.put(new PropertySimple(customPropName, customPropValue)); config.put(new PropertySimple(onePropName, onePropValue)); BundleDeployment deployment = new BundleDeployment(); deployment.setId(789); deployment.setName("test bundle 2 deployment name - REVERT"); deployment.setBundleVersion(bundleVersion); deployment.setConfiguration(config); deployment.setDestination(destination); // copy the test archive file to the bundle files dir FileUtil.copyFile( new File("src/test/resources/test-bundle-two-archive.zip"), new File(this.bundleFilesDir, "test-bundle-two-archive.zip")); // create test.properties file in the bundle files dir File file1 = new File(this.bundleFilesDir, "test.properties"); Properties props = new Properties(); props.setProperty(customPropName, "@@" + customPropName + "@@"); FileOutputStream outputStream = new FileOutputStream(file1); props.store(outputStream, "test.properties comment"); outputStream.close(); BundleDeployRequest request = new BundleDeployRequest(); request.setBundleFilesLocation(this.bundleFilesDir); request.setResourceDeployment(new BundleResourceDeployment(deployment, null)); request.setBundleManagerProvider(new MockBundleManagerProvider()); request.setAbsoluteDestinationDirectory(this.destDir); request.setRevert(true); BundleDeployResult results = plugin.deployBundle(request); assertResultsSuccess(results); // test that the prop was replaced in raw file test.properties Properties realizedProps = new Properties(); loadProperties( realizedProps, new FileInputStream(new File(this.destDir, "config/test.properties"))); assert customPropValue.equals(realizedProps.getProperty(customPropName)) : "didn't replace prop"; // test that the archive was extracted properly. These are the files in the archive: // zero-file.txt (content: "zero") // one/one-file.txt (content: "@@one.prop@@") <-- recipe says this is to be replaced // two/two-file.txt (content: "@@two.prop@@") <-- recipe does not say to replace this // REMOVED: three/three-file.txt <-- this existed in the upgrade, but not the original // ----- the following was backed up and should be reverted // extra/extra-file.txt File zeroFile = new File(this.destDir, "zero-file.txt"); File oneFile = new File(this.destDir, "one/one-file.txt"); File twoFile = new File(this.destDir, "two/two-file.txt"); File threeFile = new File(this.destDir, "three/three-file.txt"); assert zeroFile.exists() : "zero file should have been restored during revert"; assert oneFile.exists() : "one file missing"; assert twoFile.exists() : "two file missing"; assert !threeFile.exists() : "three file should have been deleted during revert"; assert readFile(zeroFile).startsWith("zero") : "bad restore of zero file"; assert readFile(oneFile).startsWith(onePropValue); assert readFile(twoFile).startsWith("@@two.prop@@"); // make sure the revert restored the backed up files File extraFile = new File(this.destDir, "extra/extra-file.txt"); assert extraFile.exists() : "extra file should have been restored due to revert deployment request"; assert readFile(extraFile).startsWith("extra") : "bad restore of extra file"; DeploymentsMetadata metadata = new DeploymentsMetadata(this.destDir); DeploymentProperties deploymentProps = metadata.getDeploymentProperties(deployment.getId()); assert deploymentProps.getDeploymentId() == deployment.getId(); assert deploymentProps.getBundleName().equals(bundle.getName()); assert deploymentProps.getBundleVersion().equals(bundleVersion.getVersion()); assert deploymentProps.getManageRootDir() == true; DeploymentProperties currentProps = metadata.getCurrentDeploymentProperties(); assert deploymentProps.equals(currentProps); // check the backup directory - note, clean flag is irrelevent when determining what should be // backed up File backupDir = metadata.getDeploymentBackupDirectory(deployment.getId()); File ignoredBackupFile = new File(backupDir, "ignore/ignore-file.txt"); assert ignoredBackupFile.isFile() : "old recipe didn't ignore these, should be backed up"; DeploymentProperties previousProps = metadata.getPreviousDeploymentProperties(789); assert previousProps != null : "There should be previous deployment metadata"; assert previousProps.getDeploymentId() == 456 : "bad previous deployment metadata"; // testAntBundleUpgrade used 456 assert previousProps.getBundleName().equals(deploymentProps.getBundleName()); assert previousProps .getBundleVersion() .equals("3.0"); // testAntBundleUpgrade deployed version 3.0 }
/** * Downloads the bundle's files into the bundle plugin's tmp directory and returns that tmp * directory. * * @param resourceDeployment access to deployment information, including what bundle files need to * be downloaded * @param downloadDir location where the bundle files should be downloaded * @return map of the package versions to their files that were downloaded * @throws Exception */ private Map<PackageVersion, File> downloadBundleFiles( BundleResourceDeployment resourceDeployment, File downloadDir) throws Exception { BundleDeployment bundleDeployment = resourceDeployment.getBundleDeployment(); BundleVersion bundleVersion = bundleDeployment.getBundleVersion(); Map<PackageVersion, File> packageVersionFiles = new HashMap<PackageVersion, File>(); List<PackageVersion> packageVersions = getAllBundleVersionPackageVersions(bundleVersion); for (PackageVersion packageVersion : packageVersions) { File packageFile = new File(downloadDir, packageVersion.getFileName()); try { verifyHash(packageVersion, packageFile); } catch (Exception e) { // file either doesn't exist or it hash doesn't match, download a new copy packageFile.getParentFile().mkdirs(); FileOutputStream fos = new FileOutputStream(packageFile); try { auditDeployment( resourceDeployment, AUDIT_FILE_DOWNLOAD_STARTED, packageVersion.getDisplayName(), "Downloading [" + packageVersion + "]"); long size = getFileContent(packageVersion, fos); if (packageVersion.getFileSize() != null && size != packageVersion.getFileSize().longValue()) { String message = "Downloaded bundle file [" + packageVersion + "] but its size was [" + size + "] when it was expected to be [" + packageVersion.getFileSize() + "]."; log.warn(message); auditDeployment( resourceDeployment, AUDIT_FILE_DOWNLOAD_ENDED, packageVersion.getDisplayName(), null, BundleResourceDeploymentHistory.Status.WARN, message, null); } else { auditDeployment( resourceDeployment, AUDIT_FILE_DOWNLOAD_ENDED, packageVersion.getDisplayName(), "Download complete for [" + packageVersion + "]"); } } catch (Exception e2) { String message = "Failed to downloaded bundle file [" + packageVersion + "] " + e2; log.warn(message); auditDeployment( resourceDeployment, AUDIT_FILE_DOWNLOAD_ENDED, packageVersion.getDisplayName(), null, BundleResourceDeploymentHistory.Status.FAILURE, message, null); } finally { fos.close(); } // now try to verify it again, if this throws an exception, that is very bad and we need to // abort verifyHash(packageVersion, packageFile); } packageVersionFiles.put(packageVersion, packageFile); } return packageVersionFiles; }
@Override public BundlePurgeResponse purge(BundlePurgeRequest request) { final BundlePurgeResponse response = new BundlePurgeResponse(); try { final BundleResourceDeployment resourceDeployment = request.getLiveBundleResourceDeployment(); final BundleDeployment bundleDeployment = resourceDeployment.getBundleDeployment(); // find the resource that will purge the bundle InventoryManager im = getInventoryManager(); BundleType bundleType = bundleDeployment.getBundleVersion().getBundle().getBundleType(); ResourceType resourceType = bundleType.getResourceType(); Set<Resource> resources = im.getResourcesWithType(resourceType); if (resources.isEmpty()) { throw new Exception("No bundle plugin supports bundle type [" + bundleType + "]"); } final int bundleHandlerResourceId = resources.iterator().next().getId(); final ResourceContainer resourceContainer = im.getResourceContainer(bundleHandlerResourceId); if (null == resourceContainer.getResourceContext()) { throw new Exception( "No bundle plugin resource available to handle purge for bundle type [" + bundleType + "]. Ensure the bundle plugin is deployed and its resource is imported into inventory."); } // purge the bundle utilizing the bundle facet object String deploymentMessage = "Deployment [" + bundleDeployment + "] to be purged via [" + resourceDeployment.getResource() + "]"; auditDeployment( resourceDeployment, AUDIT_PURGE_STARTED, bundleDeployment.getName(), deploymentMessage); File absoluteDestDir = getAbsoluteDestinationDir(request.getLiveBundleResourceDeployment()); org.rhq.core.pluginapi.bundle.BundlePurgeRequest purgeRequest = new org.rhq.core.pluginapi.bundle.BundlePurgeRequest(); purgeRequest.setBundleManagerProvider(this); purgeRequest.setLiveResourceDeployment(resourceDeployment); purgeRequest.setAbsoluteDestinationDirectory(absoluteDestDir); // get the bundle facet object that will process the bundle and call it to start the purge int facetMethodTimeout = 30 * 60 * 1000; // 30 minutes should be enough time for the bundle plugin to purge everything BundleFacet bundlePluginComponent = getBundleFacet(bundleHandlerResourceId, facetMethodTimeout); BundlePurgeResult result = bundlePluginComponent.purgeBundle(purgeRequest); if (result.isSuccess()) { auditDeployment( resourceDeployment, AUDIT_PURGE_ENDED, bundleDeployment.getName(), deploymentMessage); } else { response.setErrorMessage(result.getErrorMessage()); auditDeployment( resourceDeployment, AUDIT_PURGE_ENDED, bundleDeployment.getName(), null, Status.FAILURE, "Failed: " + deploymentMessage, result.getErrorMessage()); } } catch (Throwable t) { log.error("Failed to purge bundle: " + request, t); response.setErrorMessage(t); } return response; }
@Override public BundleScheduleResponse schedule(final BundleScheduleRequest request) { final BundleScheduleResponse response = new BundleScheduleResponse(); try { final BundleResourceDeployment resourceDeployment = request.getBundleResourceDeployment(); final BundleDeployment bundleDeployment = resourceDeployment.getBundleDeployment(); // find the resource that will handle the bundle processing InventoryManager im = getInventoryManager(); BundleType bundleType = bundleDeployment.getBundleVersion().getBundle().getBundleType(); ResourceType resourceType = bundleType.getResourceType(); Set<Resource> resources = im.getResourcesWithType(resourceType); if (resources.isEmpty()) { throw new Exception("No bundle plugin supports bundle type [" + bundleType + "]"); } final int bundleHandlerResourceId = resources.iterator().next().getId(); final ResourceContainer resourceContainer = im.getResourceContainer(bundleHandlerResourceId); if (null == resourceContainer.getResourceContext()) { throw new Exception( "No bundle plugin resource available to handle deployment for bundle type [" + bundleType + "]. Ensure the bundle plugin is deployed and its resource is imported into inventory."); } auditDeployment( resourceDeployment, AUDIT_DEPLOYMENT_SCHEDULED, bundleDeployment.getName(), "Scheduled deployment time: " + request.getRequestedDeployTimeAsString()); Runnable deployerRunnable = new Runnable() { public void run() { try { // pull down the bundle files that the plugin will need in order to process the // bundle File pluginTmpDir = resourceContainer.getResourceContext().getTemporaryDirectory(); File bundleFilesDir = new File( pluginTmpDir, "bundle-versions/" + bundleDeployment.getBundleVersion().getId()); bundleFilesDir.mkdirs(); // clean up any old downloads we may have retrieved before. This helps clean out // our temp directory so we don't unnecessarily fill up our file system with // obsolete files removeOldDownloadedBundleFiles(bundleFilesDir); // now download the bundle files we need for the current deployment Map<PackageVersion, File> downloadedFiles = downloadBundleFiles(resourceDeployment, bundleFilesDir); // deploy the bundle utilizing the bundle facet object String deploymentMessage = "Deployment [" + bundleDeployment + "] to [" + resourceDeployment.getResource() + "]"; auditDeployment( resourceDeployment, AUDIT_DEPLOYMENT_STARTED, bundleDeployment.getName(), deploymentMessage); File absoluteDestDir = getAbsoluteDestinationDir(request.getBundleResourceDeployment()); BundleDeployRequest deployRequest = new BundleDeployRequest(); deployRequest.setBundleManagerProvider(BundleManager.this); deployRequest.setResourceDeployment(resourceDeployment); deployRequest.setBundleFilesLocation(bundleFilesDir); deployRequest.setPackageVersionFiles(downloadedFiles); deployRequest.setCleanDeployment(request.isCleanDeployment()); deployRequest.setRevert(request.isRevert()); deployRequest.setAbsoluteDestinationDirectory(absoluteDestDir); // get the bundle facet object that will process the bundle and call it to start the // deployment int facetMethodTimeout = 4 * 60 * 60 * 1000; // 4 hours is given to the bundle plugin to do its thing BundleFacet bundlePluginComponent = getBundleFacet(bundleHandlerResourceId, facetMethodTimeout); BundleDeployResult result = bundlePluginComponent.deployBundle(deployRequest); if (result.isSuccess()) { completeDeployment( resourceDeployment, BundleDeploymentStatus.SUCCESS, deploymentMessage); } else { completeDeployment( resourceDeployment, BundleDeploymentStatus.FAILURE, result.getErrorMessage()); } } catch (InterruptedException ie) { log.error("Failed to complete bundle deployment due to interrupt", ie); completeDeployment( resourceDeployment, BundleDeploymentStatus.FAILURE, "Deployment interrupted"); } catch (Throwable t) { log.error("Failed to complete bundle deployment", t); completeDeployment( resourceDeployment, BundleDeploymentStatus.FAILURE, "Deployment failed: " + ThrowableUtil.getAllMessages(t)); } } }; this.deployerThreadPool.execute(deployerRunnable); } catch (Throwable t) { log.error("Failed to schedule bundle request: " + request, t); response.setErrorMessage(t); } return response; }