use of io.fabric8.patch.management.FeatureUpdate in project fabric8 by jboss-fuse.
the class ServiceImpl method bundleUpdatesInPatch.
/**
* Returns a list of {@link BundleUpdate} for single patch, taking into account already discovered updates
* @param patch
* @param allBundles
* @param bundleUpdateLocations out parameter that gathers update locations for bundles across patches
* @param history
* @param updatesForBundleKeys
* @param kind
* @param coreBundles
* @param featureUpdatesInThisPatch
* @return
* @throws IOException
*/
private List<BundleUpdate> bundleUpdatesInPatch(Patch patch, Bundle[] allBundles, Map<Bundle, String> bundleUpdateLocations, BundleVersionHistory history, Map<String, BundleUpdate> updatesForBundleKeys, PatchKind kind, Map<String, Bundle> coreBundles, List<FeatureUpdate> featureUpdatesInThisPatch) throws Exception {
List<BundleUpdate> updatesInThisPatch = new LinkedList<>();
// for ROLLUP patch we can check which bundles AREN'T updated by this patch - we have to reinstall them
// at the same version as existing one. "no update" means "require install after clearing cache"
// Initially all bundles need update. If we find an update in patch, we remove a key from this map
Map<String, Bundle> updateNotRequired = new LinkedHashMap<>();
// // let's keep {symbolic name -> list of versions} mapping
// MultiMap<String, Version> allBundleVersions = new MultiMap<>();
// bundle location -> bundle key (symbolic name|updateable version)
Map<String, String> locationsOfBundleKeys = new HashMap<>();
for (Bundle b : allBundles) {
if (b.getSymbolicName() == null) {
continue;
}
Version v = b.getVersion();
Version updateableVersion = new Version(v.getMajor(), v.getMinor(), 0);
String key = String.format("%s|%s", stripSymbolicName(b.getSymbolicName()), updateableVersion.toString());
// symbolic name, differing at micro version only
if (!coreBundles.containsKey(stripSymbolicName(b.getSymbolicName()))) {
updateNotRequired.put(key, b);
} else {
// let's key core (etc/startup.properties) bundles by symbolic name only - there should be only
// one version of symbolic name
updateNotRequired.put(stripSymbolicName(b.getSymbolicName()), b);
}
// allBundleVersions.put(stripSymbolicName(b.getSymbolicName()), b.getVersion());
String location = b.getLocation();
if (location != null && location.startsWith("mvn:") && location.contains("//")) {
// special case for mvn:org.ops4j.pax.url/pax-url-wrap/2.4.7//uber
location = location.replace("//", "/jar/");
}
locationsOfBundleKeys.put(location, key);
}
// let's prepare a set of bundle keys that are part of features that will be updated/reinstalled - those
// bundle keys don't have to be reinstalled separately
Set<String> bundleKeysFromFeatures = new HashSet<>();
if (featureUpdatesInThisPatch != null) {
for (FeatureUpdate featureUpdate : featureUpdatesInThisPatch) {
if (featureUpdate.getName() != null) {
// this is either installation or update of single feature
String fName = featureUpdate.getName();
String fVersion = featureUpdate.getPreviousVersion();
Feature f = featuresService.getFeature(fName, fVersion);
for (BundleInfo bundleInfo : f.getBundles()) {
if (/*!bundleInfo.isDependency() && */
locationsOfBundleKeys.containsKey(bundleInfo.getLocation())) {
bundleKeysFromFeatures.add(locationsOfBundleKeys.get(bundleInfo.getLocation()));
}
}
for (Conditional cond : f.getConditional()) {
for (BundleInfo bundleInfo : cond.getBundles()) {
if (/*!bundleInfo.isDependency() && */
locationsOfBundleKeys.containsKey(bundleInfo.getLocation())) {
bundleKeysFromFeatures.add(locationsOfBundleKeys.get(bundleInfo.getLocation()));
}
}
}
}
}
}
for (String newLocation : patch.getPatchData().getBundles()) {
// [symbolicName, version] of the new bundle
String[] symbolicNameVersion = helper.getBundleIdentity(newLocation);
if (symbolicNameVersion == null || symbolicNameVersion[0] == null) {
continue;
}
String sn = stripSymbolicName(symbolicNameVersion[0]);
String vr = symbolicNameVersion[1];
Version newVersion = VersionTable.getVersion(vr);
Version updateableVersion = new Version(newVersion.getMajor(), newVersion.getMinor(), 0);
// this bundle update from a patch may be applied only to relevant bundle|updateable-version, not to
// *every* bundle with exact symbolic name
String key = null;
if (!coreBundles.containsKey(sn)) {
key = String.format("%s|%s", sn, updateableVersion.toString());
} else {
key = sn;
}
// if existing bundle is within this range, update is possible
VersionRange range = getUpdateableRange(patch, newLocation, newVersion);
if (coreBundles.containsKey(sn)) {
// so we lower down the lowest possible version of core bundle that we can update
if (range == null) {
range = new VersionRange(false, Version.emptyVersion, newVersion, true);
} else {
range = new VersionRange(false, Version.emptyVersion, range.getCeiling(), true);
}
} else if (range != null) {
// if range is specified on non core bundle, the key should be different - updateable
// version should be taken from range
key = String.format("%s|%s", sn, range.getFloor().toString());
}
Bundle bundle = updateNotRequired.get(key);
if (bundle == null && coreBundles.containsKey(sn)) {
bundle = updateNotRequired.get(sn);
}
if (bundle == null || range == null) {
// this patch ships a bundle that can't be used as an update for ANY currently installed bundle
if (kind == PatchKind.NON_ROLLUP) {
// which is strange, because non rollup patches should update existing bundles...
if (range == null) {
System.err.printf("Skipping bundle %s - unable to process bundle without a version range configuration%n", newLocation);
} else {
// range is fine, we simply didn't find installed bundle at all - bundle from patch
// will be stored in ${karaf.default.repository}, but not used as an update
}
}
continue;
}
Version oldVersion = bundle.getVersion();
if (range.contains(oldVersion)) {
String oldLocation = history.getLocation(bundle);
if ("org.ops4j.pax.url.mvn".equals(sn)) {
Artifact artifact = Utils.mvnurlToArtifact(newLocation, true);
if (artifact != null) {
URL location = new File(repository, String.format("org/ops4j/pax/url/pax-url-aether/%1$s/pax-url-aether-%1$s.jar", artifact.getVersion())).toURI().toURL();
newLocation = location.toString();
}
}
int startLevel = bundle.adapt(BundleStartLevel.class).getStartLevel();
int state = bundle.getState();
BundleUpdate update = new BundleUpdate(sn, newVersion.toString(), newLocation, oldVersion.toString(), oldLocation, startLevel, state);
if (bundleKeysFromFeatures.contains(key) || coreBundles.containsKey(sn)) {
update.setIndependent(false);
}
updatesInThisPatch.add(update);
updateNotRequired.remove(key);
if (coreBundles.containsKey(sn)) {
updateNotRequired.remove(sn);
}
// Merge result
BundleUpdate oldUpdate = updatesForBundleKeys.get(key);
if (oldUpdate != null) {
Version upv = null;
if (oldUpdate.getNewVersion() != null) {
upv = VersionTable.getVersion(oldUpdate.getNewVersion());
}
if (upv == null || upv.compareTo(newVersion) < 0) {
// other patch contains newer update for a bundle
updatesForBundleKeys.put(key, update);
bundleUpdateLocations.put(bundle, newLocation);
}
} else {
// this is the first update of the bundle
updatesForBundleKeys.put(key, update);
bundleUpdateLocations.put(bundle, newLocation);
}
}
}
if (kind == PatchKind.ROLLUP) {
// user features) and we have (at least try) to install them after restart.
for (Bundle b : updateNotRequired.values()) {
if (b.getSymbolicName() == null) {
continue;
}
String symbolicName = stripSymbolicName(b.getSymbolicName());
Version v = b.getVersion();
Version updateableVersion = new Version(v.getMajor(), v.getMinor(), 0);
String key = String.format("%s|%s", symbolicName, updateableVersion.toString());
int startLevel = b.adapt(BundleStartLevel.class).getStartLevel();
int state = b.getState();
BundleUpdate update = new BundleUpdate(symbolicName, null, null, v.toString(), history.getLocation(b), startLevel, state);
if (bundleKeysFromFeatures.contains(key) || coreBundles.containsKey(symbolicName)) {
// we don't have to install it separately
update.setIndependent(false);
}
updatesInThisPatch.add(update);
updatesForBundleKeys.put(key, update);
}
}
return updatesInThisPatch;
}
use of io.fabric8.patch.management.FeatureUpdate 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.patch.management.FeatureUpdate in project fabric8 by jboss-fuse.
the class ServiceImpl method featureUpdatesInPatch.
/**
* Returns a list of {@link FeatureUpdate} for single patch, taking into account already discovered updates
* @param patch
* @param updatesForFeatureKeys
* @param kind
* @return
*/
private List<FeatureUpdate> featureUpdatesInPatch(Patch patch, Map<String, FeatureUpdate> updatesForFeatureKeys, PatchKind kind) throws Exception {
Set<String> addedRepositoryNames = new HashSet<>();
HashMap<String, Repository> after = null;
try {
List<FeatureUpdate> updatesInThisPatch = new LinkedList<>();
/*
* Two pairs of features makes feature names not enough to be a key:
* <feature name="openjpa" description="Apache OpenJPA 2.2.x persistent engine support" version="2.2.2" resolver="(obr)">
* <feature name="openjpa" description="Apache OpenJPA 2.3.x persistence engine support" version="2.3.0" resolver="(obr)">
* and
* <feature name="activemq-camel" version="5.11.0.redhat-621039" resolver="(obr)" start-level="50">
* <feature name="activemq-camel" version="1.2.0.redhat-621039" resolver="(obr)">
*/
// install the new feature repos, tracking the set the were
// installed before and after
// (e.g, "karaf-enterprise-2.4.0.redhat-620133" -> Repository)
Map<String, Repository> before = new HashMap<>(getAvailableFeatureRepositories());
for (String url : patch.getPatchData().getFeatureFiles()) {
featuresService.addRepository(new URI(url));
}
after = getAvailableFeatureRepositories();
// track which old repos provide which features to find out if we have new repositories for those features
// key is name|version (don't expect '|' to be part of name...)
// assume that [feature-name, feature-version{major,minor,0,0}] is defined only in single repository
Map<String, String> featuresInOldRepositories = new HashMap<>();
// key is only name, without version - used when there's single feature in old and in new repositories
MultiMap<String, String> singleFeaturesInOldRepositories = new MultiMap<>();
Map<String, Version> actualOldFeatureVersions = new HashMap<>();
for (Repository existingRepository : before.values()) {
for (Feature feature : existingRepository.getFeatures()) {
Version v = Utils.getOsgiVersion(feature.getVersion());
Version lowestUpdateableVersion = new Version(v.getMajor(), v.getMinor(), 0);
// assume that we can update feature XXX-2.2.3 to XXX-2.2.142, but not to XXX-2.3.0.alpha-1
String key = String.format("%s|%s", feature.getName(), lowestUpdateableVersion.toString());
featuresInOldRepositories.put(key, existingRepository.getURI().toString());
singleFeaturesInOldRepositories.put(feature.getName(), existingRepository.getURI().toString());
actualOldFeatureVersions.put(key, v);
}
}
// Use the before and after set to figure out which repos were added.
addedRepositoryNames = new HashSet<>(after.keySet());
addedRepositoryNames.removeAll(before.keySet());
// track the new repositories where we can find old features
Map<String, String> featuresInNewRepositories = new HashMap<>();
MultiMap<String, String> singleFeaturesInNewRepositories = new MultiMap<>();
Map<String, String> actualNewFeatureVersions = new HashMap<>();
MultiMap<String, String> singleActualNewFeatureVersions = new MultiMap<>();
// Figure out which old repos were updated: Do they have feature
// with the same name as one contained in a repo being added?
// and do they have update'able version? (just like with bundles)
Set<String> oldRepositoryNames = new HashSet<String>();
for (String addedRepositoryName : addedRepositoryNames) {
Repository added = after.get(addedRepositoryName);
for (Feature feature : added.getFeatures()) {
Version v = Utils.getOsgiVersion(feature.getVersion());
Version lowestUpdateableVersion = new Version(v.getMajor(), v.getMinor(), 0);
String key = String.format("%s|%s", feature.getName(), lowestUpdateableVersion.toString());
featuresInNewRepositories.put(key, addedRepositoryName);
singleFeaturesInNewRepositories.put(feature.getName(), addedRepositoryName);
actualNewFeatureVersions.put(key, v.toString());
singleActualNewFeatureVersions.put(feature.getName(), v.toString());
String oldRepositoryWithUpdateableFeature = featuresInOldRepositories.get(key);
if (oldRepositoryWithUpdateableFeature == null && singleFeaturesInOldRepositories.get(feature.getName()) != null && singleFeaturesInOldRepositories.get(feature.getName()).size() == 1) {
oldRepositoryWithUpdateableFeature = singleFeaturesInOldRepositories.get(feature.getName()).get(0);
}
if (oldRepositoryWithUpdateableFeature != null) {
// track the old repository to be removed
oldRepositoryNames.add(oldRepositoryWithUpdateableFeature);
}
}
}
// We need to uninstall them. Before we uninstall, track which features were installed.
for (String oldRepositoryName : oldRepositoryNames) {
Repository repository = before.get(oldRepositoryName);
for (Feature feature : repository.getFeatures()) {
if (featuresService.isInstalled(feature)) {
Version v = Utils.getOsgiVersion(feature.getVersion());
Version lowestUpdateableVersion = new Version(v.getMajor(), v.getMinor(), 0);
String key = String.format("%s|%s", feature.getName(), lowestUpdateableVersion.toString());
String newRepositoryName = featuresInNewRepositories.get(key);
String newVersion = actualNewFeatureVersions.get(key);
if (newRepositoryName == null) {
// feature from 1.1.1 to 1.3.0
if (singleFeaturesInOldRepositories.get(feature.getName()) != null && singleFeaturesInOldRepositories.get(feature.getName()).size() == 1 && singleFeaturesInNewRepositories.get(feature.getName()) != null && singleFeaturesInNewRepositories.get(feature.getName()).size() == 1) {
newRepositoryName = singleFeaturesInNewRepositories.get(feature.getName()).get(0);
}
}
if (newVersion == null) {
if (singleActualNewFeatureVersions.get(feature.getName()) != null && singleActualNewFeatureVersions.get(feature.getName()).size() == 1) {
newVersion = singleActualNewFeatureVersions.get(feature.getName()).get(0);
}
}
FeatureUpdate featureUpdate = null;
if (newVersion != null && newRepositoryName != null) {
featureUpdate = new FeatureUpdate(feature.getName(), after.get(oldRepositoryName).getURI().toString(), feature.getVersion(), after.get(newRepositoryName).getURI().toString(), newVersion);
} else {
// we didn't find an update for installed features among feature repositories from patch
// which means we have to preserve both the feature and the repository - this may
// be user's feature
featureUpdate = new FeatureUpdate(feature.getName(), after.get(oldRepositoryName).getURI().toString(), feature.getVersion(), null, null);
}
updatesInThisPatch.add(featureUpdate);
// Merge result
FeatureUpdate oldUpdate = updatesForFeatureKeys.get(key);
if (oldUpdate != null) {
Version upv = null, newV = null;
if (oldUpdate.getNewVersion() != null) {
upv = VersionTable.getVersion(oldUpdate.getNewVersion());
}
if (newVersion != null) {
newV = VersionTable.getVersion(newVersion);
}
if (upv == null && newV == null) {
// weird...
} else {
if (upv == null || (newV != null && upv.compareTo(newV) < 0)) {
// other patch contains newer update for the feature
updatesForFeatureKeys.put(key, featureUpdate);
}
}
} else {
// this is the first update of the bundle
updatesForFeatureKeys.put(key, featureUpdate);
}
}
}
}
// now let's see if there are repositories that are NOT updated (either they're not available in patch
// (like user feature repositories) or simply didn't change (like jclouds 1.8.1 between Fuse 6.2 and 6.2.1)
Set<String> unchangedRepositoryNames = new HashSet<>(before.keySet());
unchangedRepositoryNames.removeAll(oldRepositoryNames);
for (String unchangedRepositoryName : unchangedRepositoryNames) {
Repository repository = before.get(unchangedRepositoryName);
boolean hasInstalledFeatures = false;
for (Feature feature : repository.getFeatures()) {
if (featuresService.isInstalled(feature)) {
FeatureUpdate featureUpdate = new FeatureUpdate(feature.getName(), after.get(unchangedRepositoryName).getURI().toString(), feature.getVersion(), null, null);
hasInstalledFeatures = true;
// preserve unchanged/user feature - install after restart
updatesInThisPatch.add(featureUpdate);
// the key doesn't matter
updatesForFeatureKeys.put(String.format("%s|%s", feature.getName(), feature.getVersion()), featureUpdate);
}
}
if (!hasInstalledFeatures) {
// we have to preserve unchanged/user feature repository - even if it had no installed features
// this featureUpdate means - "restore feature repository only"
FeatureUpdate featureUpdate = new FeatureUpdate(null, after.get(unchangedRepositoryName).getURI().toString(), null, null, null);
updatesInThisPatch.add(featureUpdate);
updatesForFeatureKeys.put(String.format("REPOSITORY_TO_ADD:%s", after.get(unchangedRepositoryName).getURI().toString()), featureUpdate);
}
}
return updatesInThisPatch;
} catch (Exception e) {
throw new PatchException(e.getMessage(), e);
} finally {
// we'll add new feature repositories again later. here we've added them only to track the updates
if (after != null) {
for (String repo : addedRepositoryNames) {
if (after.get(repo) != null) {
featuresService.removeRepository(after.get(repo).getURI(), false);
}
}
}
}
}
use of io.fabric8.patch.management.FeatureUpdate in project fabric8 by jboss-fuse.
the class ServiceImpl method resumePendingPatchTasks.
/**
* Upon startup (activation), we check if there are any *.patch.pending files. if yes, we're finishing the
* installation
*/
private void resumePendingPatchTasks() throws IOException {
File[] pendingPatches = patchDir.listFiles(new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.exists() && pathname.getName().endsWith(".pending");
}
});
if (pendingPatches == null || pendingPatches.length == 0) {
return;
}
for (File pending : pendingPatches) {
Pending what = Pending.valueOf(FileUtils.readFileToString(pending));
String name = pending.getName().replaceFirst("\\.pending$", "");
if (patchManagement.isStandaloneChild()) {
if (name.endsWith("." + System.getProperty("karaf.name") + ".patch")) {
name = name.replaceFirst("\\." + System.getProperty("karaf.name"), "");
} else {
continue;
}
}
File patchFile = new File(pending.getParentFile(), name);
if (!patchFile.isFile()) {
System.out.println("Ignoring patch result file: " + patchFile.getName());
continue;
}
PatchData patchData = PatchData.load(new FileInputStream(patchFile));
Patch patch = patchManagement.loadPatch(new PatchDetailsRequest(patchData.getId()));
System.out.printf("Resume %s of %spatch \"%s\"%n", what == Pending.ROLLUP_INSTALLATION ? "installation" : "rollback", patch.getPatchData().isRollupPatch() ? "rollup " : "", patch.getPatchData().getId());
PatchResult result = patch.getResult();
if (patchManagement.isStandaloneChild()) {
result = result.getChildPatches().get(System.getProperty("karaf.name"));
if (result == null) {
System.out.println("Ignoring patch result file: " + patchFile.getName());
continue;
}
}
// feature time
Set<String> newRepositories = new LinkedHashSet<>();
Set<String> features = new LinkedHashSet<>();
for (FeatureUpdate featureUpdate : result.getFeatureUpdates()) {
if (featureUpdate.getName() == null && featureUpdate.getPreviousRepository() != null) {
// feature was not shipped by patch
newRepositories.add(featureUpdate.getPreviousRepository());
} else if (featureUpdate.getNewRepository() == null) {
// feature was not changed by patch
newRepositories.add(featureUpdate.getPreviousRepository());
features.add(String.format("%s|%s", featureUpdate.getName(), featureUpdate.getPreviousVersion()));
} else {
// feature was shipped by patch
if (what == Pending.ROLLUP_INSTALLATION) {
newRepositories.add(featureUpdate.getNewRepository());
features.add(String.format("%s|%s", featureUpdate.getName(), featureUpdate.getNewVersion()));
} else {
newRepositories.add(featureUpdate.getPreviousRepository());
features.add(String.format("%s|%s", featureUpdate.getName(), featureUpdate.getPreviousVersion()));
}
}
}
for (String repo : newRepositories) {
System.out.println("Restoring feature repository: " + repo);
try {
featuresService.addRepository(URI.create(repo));
} catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace(System.err);
System.err.flush();
}
}
for (String f : features) {
String[] fv = f.split("\\|");
System.out.printf("Restoring feature %s/%s%n", fv[0], fv[1]);
try {
featuresService.installFeature(fv[0], fv[1]);
} catch (Exception e) {
System.err.println(e.getMessage());
e.printStackTrace(System.err);
System.err.flush();
}
}
for (BundleUpdate update : result.getBundleUpdates()) {
if (!update.isIndependent()) {
continue;
}
String location = null;
if (update.getNewVersion() == null) {
System.out.printf("Restoring bundle %s from %s%n", update.getSymbolicName(), update.getPreviousLocation());
location = update.getPreviousLocation();
} else {
if (what == Pending.ROLLUP_INSTALLATION) {
System.out.printf("Updating bundle %s from %s%n", update.getSymbolicName(), update.getNewLocation());
location = update.getNewLocation();
} else {
System.out.printf("Downgrading bundle %s from %s%n", update.getSymbolicName(), update.getPreviousLocation());
location = update.getPreviousLocation();
}
}
try {
Bundle b = bundleContext.installBundle(location);
if (update.getStartLevel() > -1) {
b.adapt(BundleStartLevel.class).setStartLevel(update.getStartLevel());
}
switch(update.getState()) {
// ?
case Bundle.UNINSTALLED:
case Bundle.INSTALLED:
case Bundle.STARTING:
case Bundle.STOPPING:
break;
case Bundle.RESOLVED:
// ?bundleContext.getBundle(0L).adapt(org.osgi.framework.wiring.FrameworkWiring.class).resolveBundles(...);
break;
case Bundle.ACTIVE:
b.start();
break;
}
} catch (BundleException e) {
System.err.println(" - " + e.getMessage());
// e.printStackTrace(System.err);
System.err.flush();
}
}
pending.delete();
System.out.printf("%spatch \"%s\" %s successfully%n", patch.getPatchData().isRollupPatch() ? "Rollup " : "", patchData.getId(), what == Pending.ROLLUP_INSTALLATION ? "installed" : "rolled back");
if (what == Pending.ROLLUP_ROLLBACK) {
List<String> bases = patch.getResult().getKarafBases();
for (Iterator<String> iterator = bases.iterator(); iterator.hasNext(); ) {
String s = iterator.next();
if (s.startsWith(System.getProperty("karaf.name"))) {
iterator.remove();
}
}
result.setPending(null);
patch.getResult().store();
if (patch.getResult().getKarafBases().size() == 0) {
File file = new File(patchDir, patchData.getId() + ".patch.result");
file.delete();
}
if (patchManagement.isStandaloneChild()) {
File file = new File(patchDir, patchData.getId() + "." + System.getProperty("karaf.name") + ".patch.result");
if (file.isFile()) {
file.delete();
}
}
}
}
}
use of io.fabric8.patch.management.FeatureUpdate in project fabric8 by jboss-fuse.
the class OSGiPatchHelper method sortFeatureUpdates.
/**
* Sorts feature updates in the way that features listed in etc/org.apache.karaf.features.cfg:featuresBoot
* are updated first
* @param featureUpdatesInThisPatch
*/
public void sortFeatureUpdates(List<FeatureUpdate> featureUpdatesInThisPatch) throws IOException {
Properties props = new Properties();
FileInputStream stream = new FileInputStream(new File(karafHome, "etc/org.apache.karaf.features.cfg"));
props.load(stream);
IOUtils.closeQuietly(stream);
String p = props.getProperty("featuresBoot");
if (p != null) {
String[] properties = p.split("\\s,\\s");
Set<String> featuresBoot = new LinkedHashSet<>(Arrays.asList(properties));
// Set<String> featuresSpecial = new LinkedHashSet<>(Arrays.asList("cxf-specs", "cxf-core", "cxf-jaxrs"));
Set<String> featuresSpecial = new LinkedHashSet<>(Arrays.asList("fabric-cxf"));
Map<String, FeatureUpdate> newOrderedUpdates = new HashMap<>();
List<FeatureUpdate> newOtherUpdates = new LinkedList<>();
List<FeatureUpdate> newUpdates = new LinkedList<>();
for (Iterator<FeatureUpdate> iterator = featureUpdatesInThisPatch.iterator(); iterator.hasNext(); ) {
FeatureUpdate update = iterator.next();
if (update.getName() != null && (featuresBoot.contains(update.getName()) || featuresSpecial.contains(update.getName()))) {
newOrderedUpdates.put(update.getName(), update);
} else {
newOtherUpdates.add(update);
}
}
for (String fb : featuresBoot) {
if (newOrderedUpdates.containsKey(fb)) {
newUpdates.add(newOrderedUpdates.get(fb));
}
}
for (String fs : featuresSpecial) {
if (newOrderedUpdates.containsKey(fs)) {
newUpdates.add(newOrderedUpdates.get(fs));
}
}
newUpdates.addAll(newOtherUpdates);
featureUpdatesInThisPatch.clear();
featureUpdatesInThisPatch.addAll(newUpdates);
}
}
Aggregations