Search in sources :

Example 1 with FeatureUpdate

use of org.jboss.fuse.patch.management.FeatureUpdate in project fuse-karaf by jboss-fuse.

the class Presentation method displayFeatureUpdates.

/**
 * Displays a table with installed (<code>install == true</code>) or rolledback features
 * @param featureUpdates
 * @param install is this displayed during patch install (<code>true</code>) or rollback (<code>false</code>)
 */
public static void displayFeatureUpdates(Collection<FeatureUpdate> featureUpdates, boolean install) {
    Set<String> toKeep = new TreeSet<>();
    Set<String> toRemove = new TreeSet<>();
    Set<String> toAdd = new TreeSet<>();
    for (FeatureUpdate fu : featureUpdates) {
        if (install) {
            toRemove.add(fu.getPreviousRepository());
        } else if (fu.getNewRepository() != null) {
            toRemove.add(fu.getNewRepository());
        }
        if (fu.getNewRepository() != null) {
            toAdd.add(install ? fu.getNewRepository() : fu.getPreviousRepository());
        } else if (install) {
            // keep old only during installation, when rolling back rollup patch, we don't want to keep
            // any new repository
            toKeep.add(fu.getPreviousRepository());
        }
    }
    toRemove.removeAll(toKeep);
    if (toRemove.size() > 0) {
        System.out.printf("========== Repositories to remove (%d):%n", toRemove.size());
        for (String repo : toRemove) {
            System.out.println(" - " + repo);
        }
    }
    if (toAdd.size() > 0) {
        System.out.printf("========== Repositories to add (%d):%n", toAdd.size());
        for (String repo : toAdd) {
            System.out.println(" - " + repo);
        }
    }
    if (toKeep.size() > 0) {
        System.out.printf("========== Repositories to keep (%d):%n", toKeep.size());
        for (String repo : toKeep) {
            System.out.println(" - " + repo);
        }
    }
    int l1 = "[name]".length();
    int l2 = "[version]".length();
    int l3 = install ? "[new version]".length() : "[previous version]".length();
    Map<String, FeatureUpdate> map = new TreeMap<>();
    for (FeatureUpdate fu : featureUpdates) {
        if (fu.getName() == null) {
            continue;
        }
        if (fu.getName().length() > l1) {
            l1 = fu.getName().length();
        }
        if (install) {
            if (fu.getPreviousVersion().length() > l2) {
                l2 = fu.getPreviousVersion().length();
            }
            if (fu.getNewVersion() != null) {
                if (fu.getNewVersion().length() > l3) {
                    l3 = fu.getNewVersion().length();
                }
            }
        } else {
            if (fu.getNewVersion() != null) {
                if (fu.getNewVersion().length() > l2) {
                    l2 = fu.getNewVersion().length();
                }
            }
            if (fu.getPreviousVersion().length() > l3) {
                l3 = fu.getPreviousVersion().length();
            }
        }
        map.put(fu.getName(), fu);
    }
    if (map.size() > 0) {
        System.out.printf("========== Features to %s (%d):%n", install ? "update" : "downgrade", map.size());
        System.out.printf("%-" + l1 + "s   %-" + l2 + "s   %-" + l3 + "s%n", "[name]", "[version]", install ? "[new version]" : "[previous version]");
        for (FeatureUpdate fu : map.values()) {
            System.out.printf("%-" + l1 + "s   %-" + l2 + "s   %-" + l3 + "s%n", fu.getName(), install ? fu.getPreviousVersion() : fu.getNewVersion() == null ? "<reinstall>" : fu.getNewVersion(), install ? fu.getNewVersion() == null ? "<reinstall>" : fu.getNewVersion() : fu.getPreviousVersion());
        }
    }
    System.out.flush();
}
Also used : TreeSet(java.util.TreeSet) TreeMap(java.util.TreeMap) FeatureUpdate(org.jboss.fuse.patch.management.FeatureUpdate)

Example 2 with FeatureUpdate

use of org.jboss.fuse.patch.management.FeatureUpdate in project fuse-karaf 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);
    Utils.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"));
        Set<String> featuresSpecial = Collections.emptySet();
        Map<String, FeatureUpdate> newOrderedUpdates = new HashMap<>();
        List<FeatureUpdate> newOtherUpdates = new LinkedList<>();
        List<FeatureUpdate> newUpdates = new LinkedList<>();
        for (FeatureUpdate update : featureUpdatesInThisPatch) {
            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);
    }
}
Also used : LinkedHashSet(java.util.LinkedHashSet) HashMap(java.util.HashMap) Properties(java.util.Properties) File(java.io.File) FileInputStream(java.io.FileInputStream) LinkedList(java.util.LinkedList) FeatureUpdate(org.jboss.fuse.patch.management.FeatureUpdate)

Example 3 with FeatureUpdate

use of org.jboss.fuse.patch.management.FeatureUpdate in project fuse-karaf by jboss-fuse.

the class PatchServiceImpl method install.

/**
 * <p>Main installation method. Installing a patch in standalone 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);
    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<>();
        final List<String> overridesForFeatureKeys = new LinkedList<>();
        // 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;
            List<String> featureOverridesInThisPatch = null;
            if (kind == PatchKind.ROLLUP) {
                // list of feature updates for the current patch
                featureUpdatesInThisPatch = featureUpdatesInPatch(patch, updatesForFeatureKeys, kind);
                helper.sortFeatureUpdates(featureUpdatesInThisPatch);
            } else {
                // list of feature overrides (new Karaf 4.2 feature override mechanism)
                // this is collected for the purpose of summary, not to collect information needed
                // for actual override
                featureOverridesInThisPatch = featureOverridesInPatch(patch, kind);
                overridesForFeatureKeys.addAll(featureOverridesInThisPatch);
            }
            // 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);
            // 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, featureOverridesInThisPatch, result);
                    result.addChildResult(System.getProperty("karaf.name"), childResult);
                }
            } else {
                result = new PatchResult(patch.getPatchData(), simulate, System.currentTimeMillis(), bundleUpdatesInThisPatch, featureUpdatesInThisPatch, featureOverridesInThisPatch);
            }
            result.getKarafBases().add(String.format("%s | %s", System.getProperty("karaf.name"), System.getProperty("karaf.base")));
            results.put(patch.getPatchData().getId(), result);
            patch.setResult(result);
            // 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);
        }
        // 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) {
                        update(bundle, location);
                        bundle.start();
                    }
                    // replace location - to be stored in result
                    bundleUpdateLocations.put(bundle, location.toString());
                }
            }
        }
        if (kind == PatchKind.ROLLUP) {
            Presentation.displayFeatureUpdates(updatesForFeatureKeys.values(), true);
        } else {
            Presentation.displayFeatureOverrides(overridesForFeatureKeys, 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());
                    // 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..");
                            // KARAF-5179 - we need both properties set to true
                            System.setProperty("karaf.restart", "true");
                            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();
                // stop/shutdown occurs on another thread
                }
            } 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 = () -> {
                try {
                    // update bundles
                    applyChanges(bundleUpdateLocations);
                    for (String featureOverride : overridesForFeatureKeys) {
                        System.out.println("overriding feature: " + featureOverride);
                    }
                    if (overridesForFeatureKeys.size() > 0) {
                        System.out.println("refreshing features");
                        featuresService.refreshFeatures(EnumSet.noneOf(FeaturesService.Option.class));
                    }
                    // persist results of all installed patches
                    for (Patch patch : patches) {
                        PatchResult result = results.get(patch.getPatchData().getId());
                        System.out.printf("Summary of patch %s:%n", patch.getPatchData().getId());
                        PatchReport report = patch.getResult().getReport();
                        System.out.printf(" - Bundles updated: %d%n", report.getUpdatedBundles());
                        System.out.printf(" - Features updated: %d%n", report.getUpdatedFeatures());
                        System.out.printf(" - Features overriden: %d%n", report.getOverridenFeatures());
                        System.out.flush();
                        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();
    }
}
Also used : HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) PatchKind(org.jboss.fuse.patch.management.PatchKind) URL(java.net.URL) LinkedHashMap(java.util.LinkedHashMap) FeaturesService(org.apache.karaf.features.FeaturesService) BundleUpdate(org.jboss.fuse.patch.management.BundleUpdate) FeatureUpdate(org.jboss.fuse.patch.management.FeatureUpdate) Bundle(org.osgi.framework.Bundle) PatchReport(org.jboss.fuse.patch.management.PatchReport) LinkedList(java.util.LinkedList) URISyntaxException(java.net.URISyntaxException) PatchException(org.jboss.fuse.patch.management.PatchException) BundleException(org.osgi.framework.BundleException) IOException(java.io.IOException) PatchResult(org.jboss.fuse.patch.management.PatchResult) PatchException(org.jboss.fuse.patch.management.PatchException) Patch(org.jboss.fuse.patch.management.Patch) Map(java.util.Map) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) File(java.io.File)

Example 4 with FeatureUpdate

use of org.jboss.fuse.patch.management.FeatureUpdate in project fuse-karaf by jboss-fuse.

the class PatchServiceImpl method resumePendingPatchTasks.

/**
 * Upon startup (activation), we check if there are any *.patch.pending files. if yes, we're finishing the
 * installation
 */
private void resumePendingPatchTasks() {
    LOG.info("Performing \"resume pending patch tasks\"");
    try {
        File[] pendingPatches = patchDir.listFiles(pathname -> pathname.exists() && pathname.getName().endsWith(".pending"));
        if (pendingPatches == null || pendingPatches.length == 0) {
            return;
        }
        for (File pending : pendingPatches) {
            Pending what = Pending.valueOf(FileUtils.readFileToString(pending, "UTF-8"));
            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()));
                    }
                }
            }
            System.out.println("Restoring feature repositories");
            for (String repo : newRepositories) {
                try {
                    URI repositoryUri = URI.create(repo);
                    if (featuresService.getRepository(repositoryUri) == null) {
                        System.out.println("Restoring feature repository: " + repo);
                        featuresService.addRepository(repositoryUri);
                    }
                } catch (Exception e) {
                    System.err.println(e.getMessage());
                    e.printStackTrace(System.err);
                    System.err.flush();
                }
            }
            Set<String> installedFeatures = null;
            try {
                installedFeatures = Arrays.stream(featuresService.listInstalledFeatures()).map(f -> String.format("%s|%s", f.getName(), f.getVersion())).collect(Collectors.toSet());
            } catch (Exception e) {
                System.err.println(e.getMessage());
                e.printStackTrace(System.err);
                System.err.flush();
            }
            EnumSet<FeaturesService.Option> options = EnumSet.noneOf(FeaturesService.Option.class);
            Set<String> toInstall = new LinkedHashSet<>();
            System.out.println("Restoring features");
            for (String f : features) {
                if (installedFeatures == null || !installedFeatures.contains(f)) {
                    String[] fv = f.split("\\|");
                    String fid = String.format("%s/%s", fv[0], fv[1]);
                    System.out.printf("Restoring feature %s%n", fid);
                    toInstall.add(fid);
                }
            }
            try {
                if (!toInstall.isEmpty()) {
                    featuresService.installFeatures(toInstall, options);
                }
                System.out.println("Refreshing features service");
                featuresService.refreshFeatures(options);
            } 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_INSTALLATION) {
                System.out.printf("Summary of patch %s:%n", patch.getPatchData().getId());
                PatchReport report = patch.getResult().getReport();
                System.out.printf(" - Bundles updated: %d%n", report.getUpdatedBundles());
                System.out.printf(" - Features updated: %d%n", report.getUpdatedFeatures());
                System.out.printf(" - Features overriden: %d%n", report.getOverridenFeatures());
                System.out.printf("Detailed report: %s%n", new File(patch.getPatchData().getPatchLocation(), patch.getPatchData().getId() + ".patch.result.html").getCanonicalPath());
                System.out.flush();
            }
            if (what == Pending.ROLLUP_ROLLBACK) {
                List<String> bases = patch.getResult().getKarafBases();
                bases.removeIf(s -> s.startsWith(System.getProperty("karaf.name")));
                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();
                    }
                }
            }
        }
    } catch (IOException e) {
        LOG.error("Error resuming a patch: " + e.getMessage(), e);
    }
}
Also used : LinkedHashSet(java.util.LinkedHashSet) BundleStartLevel(org.osgi.framework.startlevel.BundleStartLevel) PatchDetailsRequest(org.jboss.fuse.patch.management.PatchDetailsRequest) URI(java.net.URI) FeaturesService(org.apache.karaf.features.FeaturesService) BundleException(org.osgi.framework.BundleException) BundleUpdate(org.jboss.fuse.patch.management.BundleUpdate) FeatureUpdate(org.jboss.fuse.patch.management.FeatureUpdate) PatchData(org.jboss.fuse.patch.management.PatchData) Bundle(org.osgi.framework.Bundle) PatchReport(org.jboss.fuse.patch.management.PatchReport) IOException(java.io.IOException) FileInputStream(java.io.FileInputStream) URISyntaxException(java.net.URISyntaxException) PatchException(org.jboss.fuse.patch.management.PatchException) BundleException(org.osgi.framework.BundleException) IOException(java.io.IOException) PatchResult(org.jboss.fuse.patch.management.PatchResult) File(java.io.File) Patch(org.jboss.fuse.patch.management.Patch) Pending(org.jboss.fuse.patch.management.Pending)

Example 5 with FeatureUpdate

use of org.jboss.fuse.patch.management.FeatureUpdate in project fuse-karaf by jboss-fuse.

the class PatchServiceImpl 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;
}
Also used : BundleStartLevel(org.osgi.framework.startlevel.BundleStartLevel) HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Bundle(org.osgi.framework.Bundle) Conditional(org.apache.karaf.features.Conditional) VersionRange(org.apache.felix.utils.version.VersionRange) Feature(org.apache.karaf.features.Feature) LinkedList(java.util.LinkedList) Artifact(org.jboss.fuse.patch.management.Artifact) URL(java.net.URL) LinkedHashMap(java.util.LinkedHashMap) BundleInfo(org.apache.karaf.features.BundleInfo) Version(org.osgi.framework.Version) File(java.io.File) BundleUpdate(org.jboss.fuse.patch.management.BundleUpdate) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) FeatureUpdate(org.jboss.fuse.patch.management.FeatureUpdate)

Aggregations

FeatureUpdate (org.jboss.fuse.patch.management.FeatureUpdate)6 File (java.io.File)4 HashMap (java.util.HashMap)4 LinkedHashSet (java.util.LinkedHashSet)4 LinkedList (java.util.LinkedList)4 IOException (java.io.IOException)3 URISyntaxException (java.net.URISyntaxException)3 LinkedHashMap (java.util.LinkedHashMap)3 BundleUpdate (org.jboss.fuse.patch.management.BundleUpdate)3 PatchException (org.jboss.fuse.patch.management.PatchException)3 Bundle (org.osgi.framework.Bundle)3 BundleException (org.osgi.framework.BundleException)3 FileInputStream (java.io.FileInputStream)2 URI (java.net.URI)2 URL (java.net.URL)2 HashSet (java.util.HashSet)2 Feature (org.apache.karaf.features.Feature)2 FeaturesService (org.apache.karaf.features.FeaturesService)2 Patch (org.jboss.fuse.patch.management.Patch)2 PatchReport (org.jboss.fuse.patch.management.PatchReport)2