use of io.fabric8.api.PatchException in project fabric8 by jboss-fuse.
the class ServiceImpl method install.
/**
* <p>Main installation method. Installing a patch in non-fabric mode is a matter of correct merge (cherry-pick, merge,
* rebase) of patch branch into <code>master</code> branch.</p>
* <p>Static changes are handled by git, runtime changes (bundles, features) are handled depending on patch type:<ul>
* <li>Rollup: clear OSGi bundle cache, reinstall features that were installed after restart</li>
* <li>Non-Rollup: update bundles, generate overrides.properties and update scripts to reference new versions</li>
* </ul></p>
* <p>For Rollup patches we don't update bundles - we clear the bundle cache instead.</p>
* @param patches
* @param simulate
* @param synchronous
* @return
*/
private Map<String, PatchResult> install(final Collection<Patch> patches, final boolean simulate, boolean synchronous) {
PatchKind kind = checkConsistency(patches);
checkPrerequisites(patches);
checkStandaloneChild(patches);
// checkFabric();
String transaction = null;
try {
// Compute individual patch results (patchId -> Result)
final Map<String, PatchResult> results = new LinkedHashMap<String, PatchResult>();
// current state of the framework
Bundle[] allBundles = bundleContext.getBundles();
// bundle -> url to update the bundle from (used for non-rollup patch)
final Map<Bundle, String> bundleUpdateLocations = new HashMap<>();
/* A "key" is name + "update'able version". Such version is current version with micro version == 0 */
// [symbolic name|updateable-version] -> newest update for the bundle out of all installed patches
final Map<String, BundleUpdate> updatesForBundleKeys = new LinkedHashMap<>();
// [feature name|updateable-version] -> newest update for the feature out of all installed patches
final Map<String, FeatureUpdate> updatesForFeatureKeys = new LinkedHashMap<>();
// symbolic name -> version -> location
final BundleVersionHistory history = createBundleVersionHistory();
// beginning installation transaction = creating of temporary branch in git
transaction = this.patchManagement.beginInstallation(kind);
// bundles from etc/startup.properties + felix.framework = all bundles not managed by features
// these bundles will be treated in special way
// symbolic name -> Bundle
final Map<String, Bundle> coreBundles = helper.getCoreBundles(allBundles);
// runtime info is prepared to apply runtime changes and static info is prepared to update KARAF_HOME files
for (Patch patch : patches) {
List<FeatureUpdate> featureUpdatesInThisPatch = null;
if (kind == PatchKind.ROLLUP) {
// list of feature updates for the current patch
featureUpdatesInThisPatch = featureUpdatesInPatch(patch, updatesForFeatureKeys, kind);
helper.sortFeatureUpdates(featureUpdatesInThisPatch);
}
// list of bundle updates for the current patch - for ROLLUP patch, we minimize the list of bundles
// to "restore" (install after clearing data/cache) by not including bundles that are
// already updated as part of fueatures update
List<BundleUpdate> bundleUpdatesInThisPatch = bundleUpdatesInPatch(patch, allBundles, bundleUpdateLocations, history, updatesForBundleKeys, kind, coreBundles, featureUpdatesInThisPatch);
// each patch may change files, we're not updating the main files yet - it'll be done when
// install transaction is committed
patchManagement.install(transaction, patch, bundleUpdatesInThisPatch);
// each patch may ship a migrator
if (!simulate) {
installMigratorBundle(patch);
}
// prepare patch result before doing runtime changes
PatchResult result = null;
if (patch.getResult() != null) {
result = patch.getResult();
if (patchManagement.isStandaloneChild()) {
// ENTESB-5120: "result" is actually a result of patch installation in root container
// we need dedicated result for admin:create based child container
PatchResult childResult = new PatchResult(patch.getPatchData(), simulate, System.currentTimeMillis(), bundleUpdatesInThisPatch, featureUpdatesInThisPatch, result);
result.addChildResult(System.getProperty("karaf.name"), childResult);
}
} else {
result = new PatchResult(patch.getPatchData(), simulate, System.currentTimeMillis(), bundleUpdatesInThisPatch, featureUpdatesInThisPatch);
}
result.getKarafBases().add(String.format("%s | %s", System.getProperty("karaf.name"), System.getProperty("karaf.base")));
results.put(patch.getPatchData().getId(), result);
}
// One special case
if (kind == PatchKind.NON_ROLLUP) {
// for rollup patch, this bundle will be installed from scratch
for (Map.Entry<Bundle, String> entry : bundleUpdateLocations.entrySet()) {
Bundle bundle = entry.getKey();
if (bundle.getSymbolicName() != null && "org.ops4j.pax.url.mvn".equals(stripSymbolicName(bundle.getSymbolicName()))) {
// handle this bundle specially - update it here
URL location = new URL(entry.getValue());
System.out.printf("Special update of bundle \"%s\" from \"%s\"%n", bundle.getSymbolicName(), location);
if (!simulate) {
BundleUtils.update(bundle, location);
bundle.start();
}
// replace location - to be stored in result
bundleUpdateLocations.put(bundle, location.toString());
}
}
}
Presentation.displayFeatureUpdates(updatesForFeatureKeys.values(), true);
// effectively, we will update all the bundles from this list - even if some bundles will be "updated"
// as part of feature installation
Presentation.displayBundleUpdates(updatesForBundleKeys.values(), true);
// then required repositories, features and bundles will be reinstalled
if (kind == PatchKind.ROLLUP) {
if (!simulate) {
if (patches.size() == 1) {
Patch patch = patches.iterator().next();
PatchResult result = results.get(patch.getPatchData().getId());
patch.setResult(result);
// single shot
if (patchManagement.isStandaloneChild()) {
backupService.backupDataFiles(result.getChildPatches().get(System.getProperty("karaf.name")), Pending.ROLLUP_INSTALLATION);
} else {
backupService.backupDataFiles(result, Pending.ROLLUP_INSTALLATION);
}
for (Bundle b : coreBundles.values()) {
if (b.getSymbolicName() != null && Utils.stripSymbolicName(b.getSymbolicName()).equals("org.apache.felix.fileinstall")) {
b.stop(Bundle.STOP_TRANSIENT);
break;
}
}
// update KARAF_HOME
patchManagement.commitInstallation(transaction);
if (patchManagement.isStandaloneChild()) {
result.getChildPatches().get(System.getProperty("karaf.name")).setPending(Pending.ROLLUP_INSTALLATION);
} else {
result.setPending(Pending.ROLLUP_INSTALLATION);
}
result.store();
// Some updates need a full JVM restart.
if (isJvmRestartNeeded(results)) {
boolean handlesFullRestart = Boolean.getBoolean("karaf.restart.jvm.supported");
if (handlesFullRestart) {
System.out.println("Rollup patch " + patch.getPatchData().getId() + " installed. Restarting Karaf..");
System.setProperty("karaf.restart.jvm", "true");
} else {
System.out.println("Rollup patch " + patch.getPatchData().getId() + " installed. Shutting down Karaf, please restart...");
}
} else {
// We don't need a JVM restart, so lets just do a OSGi framework restart
System.setProperty("karaf.restart", "true");
}
File karafData = new File(bundleContext.getProperty("karaf.data"));
File cleanCache = new File(karafData, "clean_cache");
cleanCache.createNewFile();
Thread.currentThread().setContextClassLoader(bundleContext.getBundle(0l).adapt(BundleWiring.class).getClassLoader());
bundleContext.getBundle(0l).stop();
}
} else {
System.out.println("Simulation only - no files and runtime data will be modified.");
patchManagement.rollbackInstallation(transaction);
}
return results;
}
// update KARAF_HOME
if (!simulate) {
patchManagement.commitInstallation(transaction);
} else {
patchManagement.rollbackInstallation(transaction);
}
if (!simulate) {
Runnable task = new Runnable() {
@Override
public void run() {
try {
// update bundles
applyChanges(bundleUpdateLocations);
// persist results of all installed patches
for (Patch patch : patches) {
PatchResult result = results.get(patch.getPatchData().getId());
patch.setResult(result);
result.store();
}
} catch (Exception e) {
e.printStackTrace(System.err);
System.err.flush();
}
}
};
if (synchronous) {
task.run();
} else {
new Thread(task).start();
}
} else {
System.out.println("Simulation only - no files and runtime data will be modified.");
}
return results;
} catch (Exception e) {
e.printStackTrace(System.err);
System.err.flush();
if (transaction != null && patchManagement != null) {
patchManagement.rollbackInstallation(transaction);
}
throw new PatchException(e.getMessage(), e);
} finally {
System.out.flush();
}
}
use of io.fabric8.api.PatchException in project fabric8 by jboss-fuse.
the class GitPatchManagementServiceIT method initializationPerformedNoBaselineDistribution.
@Test
public void initializationPerformedNoBaselineDistribution() throws IOException, GitAPIException {
freshKarafStandaloneDistro();
pm = new GitPatchManagementServiceImpl(bundleContext);
pm.start();
try {
pm.ensurePatchManagementInitialized();
fail("Should fail, because no baseline distribution is found");
} catch (PatchException e) {
assertTrue(e.getMessage().contains("Can't find baseline distribution"));
}
}
use of io.fabric8.api.PatchException in project fabric8 by jboss-fuse.
the class SimulateAction method doExecute.
@Override
protected void doExecute(Service service) throws Exception {
Patch patch = service.getPatch(patchId);
if (patch == null) {
throw new PatchException("Patch '" + patchId + "' not found");
}
if (patch.isInstalled()) {
throw new PatchException("Patch '" + patchId + "' is already installed");
}
PatchResult result = service.install(patch, true);
// display(result);
}
use of io.fabric8.api.PatchException in project fabric8 by jboss-fuse.
the class Offline method applyPatch.
protected void applyPatch(PatchData patch, ZipFile zipFile, File storage) throws IOException {
log(DEBUG, "Applying patch: " + patch.getId() + " / " + patch.getDescription());
File startupFile = new File(karafBase, "etc/startup.properties");
File overridesFile = new File(karafBase, "etc/overrides.properties");
List<String> startup = readLines(new File(karafBase, "etc/startup.properties"));
List<String> overrides = readLines(overridesFile);
List<Artifact> toExtract = new ArrayList<Artifact>();
List<Artifact> toDelete = new ArrayList<Artifact>();
for (String bundle : patch.getBundles()) {
Artifact artifact = mvnurlToArtifact(bundle, true);
if (artifact == null) {
continue;
}
// Compute patch bundle version and range
VersionRange range;
Version oVer = VersionTable.getVersion(artifact.getVersion());
String vr = patch.getVersionRange(bundle);
String override;
if (vr != null && !vr.isEmpty()) {
override = bundle + OVERRIDE_RANGE + vr;
range = VersionRange.parseVersionRange(vr);
} else {
override = bundle;
Version v1 = new Version(oVer.getMajor(), oVer.getMinor(), 0);
Version v2 = new Version(oVer.getMajor(), oVer.getMinor() + 1, 0);
range = new VersionRange(false, v1, v2, true);
}
// Process overrides.properties
boolean matching = false;
boolean added = false;
for (int i = 0; i < overrides.size(); i++) {
String line = overrides.get(i).trim();
if (!line.isEmpty() && !line.startsWith("#")) {
Artifact overrideArtifact = mvnurlToArtifact(line, true);
if (overrideArtifact != null) {
Version ver = VersionTable.getVersion(overrideArtifact.getVersion());
if (isSameButVersion(artifact, overrideArtifact) && range.contains(ver)) {
matching = true;
if (ver.compareTo(oVer) < 0) {
// Replace old override with the new one
overrides.set(i, override);
if (!added) {
log(DEBUG, "Replacing with artifact: " + override);
added = true;
}
// Remove old file
toDelete.add(overrideArtifact);
toExtract.remove(overrideArtifact);
}
}
} else {
log(WARN, "Unable to convert to artifact: " + line);
}
}
}
// If there was not matching bundles, add it
if (!matching) {
overrides.add(override);
log(DEBUG, "Adding artifact: " + override);
}
// Process startup.properties
for (int i = 0; i < startup.size(); i++) {
String line = startup.get(i).trim();
if (!line.isEmpty() && !line.startsWith("#")) {
int index = line.indexOf('=');
String mvnUrl = Utils.pathToMvnurl(line.substring(0, index));
if (mvnUrl != null) {
Artifact startupArtifact = mvnurlToArtifact(mvnUrl, true);
if (startupArtifact != null) {
Version ver = VersionTable.getVersion(startupArtifact.getVersion());
if (isSameButVersion(artifact, startupArtifact) && range.contains(ver)) {
matching = true;
// Now check versions
if (ver.compareTo(oVer) < 0) {
line = artifact.getPath() + line.substring(index);
startup.set(i, line);
log(DEBUG, "Overwriting startup.properties with: " + artifact);
added = true;
}
}
}
}
}
}
// Extract artifact
if (!matching || added) {
toExtract.add(artifact);
}
}
// Extract / delete artifacts if needed
if (zipFile != null) {
for (Artifact artifact : toExtract) {
log(DEBUG, "Extracting artifact: " + artifact);
ZipEntry entry = zipFile.getEntry("repository/" + artifact.getPath());
if (entry == null) {
log(ERROR, "Could not find artifact in patch zip: " + artifact);
continue;
}
File f = new File(karafBase, "system/" + artifact.getPath());
if (!f.isFile()) {
f.getParentFile().mkdirs();
InputStream fis = zipFile.getInputStream(entry);
FileOutputStream fos = new FileOutputStream(f);
try {
IOUtils.copy(fis, fos);
} finally {
IOUtils.closeQuietly(fis);
IOUtils.closeQuietly(fos);
}
}
}
for (Artifact artifact : toDelete) {
String fileName = artifact.getPath();
File file = new File(karafBase, "system/" + fileName);
if (file.exists()) {
log(DEBUG, "Removing old artifact " + artifact);
file.delete();
} else {
log(WARN, "Could not find: " + file);
}
}
}
overrides = new ArrayList<String>(new HashSet<String>(overrides));
Collections.sort(overrides);
writeLines(overridesFile, overrides);
writeLines(startupFile, startup);
// update the remaining patch files (using either the patch ZIP file or the patch storage location)
if (zipFile != null) {
patchFiles(patch, zipFile);
} else if (storage != null) {
patchFiles(patch, storage);
} else {
throw new PatchException("Unable to update patch files: no access to patch ZIP file or patch storage location");
}
if (patch.getMigratorBundle() != null) {
Artifact artifact = mvnurlToArtifact(patch.getMigratorBundle(), true);
if (artifact != null) {
// Copy it to the deploy dir
File src = new File(karafBase, "system/" + artifact.getPath());
File target = new File(new File(karafBase, "deploy"), artifact.getArtifactId() + ".jar");
copy(src, target);
}
}
}
use of io.fabric8.api.PatchException in project fabric8 by jboss-fuse.
the class ShowAction method doExecute.
@Override
protected void doExecute(Service service) throws Exception {
Patch patch = patchManagement.loadPatch(new PatchDetailsRequest(patchId, bundles, files, diff));
if (patch == null) {
throw new PatchException("Patch '" + patchId + "' not found");
}
System.out.println(String.format("Patch ID: %s", patch.getPatchData().getId()));
if (patch.getManagedPatch() != null) {
System.out.println(String.format("Patch Commit ID: %s", patch.getManagedPatch().getCommitId()));
}
if (bundles) {
System.out.println(String.format("#### %d Bundles%s", patch.getPatchData().getBundles().size(), patch.getPatchData().getBundles().size() == 0 ? "" : ":"));
iterate(patch.getPatchData().getBundles());
}
if (files) {
ManagedPatch details = patch.getManagedPatch();
System.out.println(String.format("#### %d Files added%s", details.getFilesAdded().size(), details.getFilesAdded().size() == 0 ? "" : ":"));
iterate(details.getFilesAdded());
System.out.println(String.format("#### %d Files modified%s", details.getFilesModified().size(), details.getFilesModified().size() == 0 ? "" : ":"));
iterate(details.getFilesModified());
System.out.println(String.format("#### %d Files removed%s", details.getFilesRemoved().size(), details.getFilesRemoved().size() == 0 ? "" : ":"));
iterate(details.getFilesRemoved());
}
if (diff) {
System.out.println("#### Patch changes:\n" + patch.getManagedPatch().getUnifiedDiff());
}
}
Aggregations