Search in sources :

Example 21 with PatchException

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

the class PatchServiceImpl method rollback.

@Override
public void rollback(final Patch patch, boolean simulate, boolean force) throws PatchException {
    final PatchResult result = !patchManagement.isStandaloneChild() ? patch.getResult() : patch.getResult().getChildPatches().get(System.getProperty("karaf.name"));
    if (result == null) {
        throw new PatchException("Patch " + patch.getPatchData().getId() + " is not installed");
    }
    if (patch.getPatchData().isRollupPatch()) {
        // we already have the "state" (feature repositories, features, bundles and their states, datafiles
        // and start-level info) stored in *.result file
        Presentation.displayFeatureUpdates(result.getFeatureUpdates(), false);
        Presentation.displayBundleUpdates(result.getBundleUpdates(), false);
        try {
            if (!simulate) {
                // let's backup data files before configadmin detects changes to etc/* files.
                backupService.backupDataFiles(result, Pending.ROLLUP_ROLLBACK);
                for (Bundle b : this.bundleContext.getBundles()) {
                    if (b.getSymbolicName() != null && Utils.stripSymbolicName(b.getSymbolicName()).equals("org.apache.felix.fileinstall")) {
                        b.stop(Bundle.STOP_TRANSIENT);
                        break;
                    }
                }
                patchManagement.rollback(patch.getPatchData());
                result.setPending(Pending.ROLLUP_ROLLBACK);
                if (patchManagement.isStandaloneChild()) {
                    result.getParent().store();
                } else {
                    result.store();
                }
                if (isJvmRestartNeeded(result)) {
                    boolean handlesFullRestart = Boolean.getBoolean("karaf.restart.jvm.supported");
                    if (handlesFullRestart) {
                        System.out.println("Rollup patch " + patch.getPatchData().getId() + " rolled back. 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() + " rolled back. 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
                return;
            } else {
                System.out.println("Simulation only - no files and runtime data will be modified.");
                return;
            }
        } catch (Exception e) {
            e.printStackTrace(System.err);
            System.err.flush();
            throw new PatchException(e.getMessage(), e);
        }
    }
    // continue with NON_ROLLUP patch
    // current state of the framework
    Bundle[] allBundles = bundleContext.getBundles();
    // check if all the bundles that were updated in patch are available (installed)
    List<BundleUpdate> badUpdates = new ArrayList<BundleUpdate>();
    for (BundleUpdate update : result.getBundleUpdates()) {
        boolean found = false;
        Version v = Version.parseVersion(update.getNewVersion() == null ? update.getPreviousVersion() : update.getNewVersion());
        for (Bundle bundle : allBundles) {
            if (bundle.getSymbolicName() == null || update.getSymbolicName() == null) {
                continue;
            }
            if (stripSymbolicName(bundle.getSymbolicName()).equals(stripSymbolicName(update.getSymbolicName())) && bundle.getVersion().equals(v)) {
                found = true;
                break;
            }
        }
        if (!found) {
            badUpdates.add(update);
        }
    }
    if (!badUpdates.isEmpty() && !force) {
        StringBuilder sb = new StringBuilder();
        sb.append("Unable to rollback patch ").append(patch.getPatchData().getId()).append(" because of the following missing bundles:\n");
        for (BundleUpdate up : badUpdates) {
            String version = up.getNewVersion() == null ? up.getPreviousVersion() : up.getNewVersion();
            sb.append(" - ").append(up.getSymbolicName()).append("/").append(version).append("\n");
        }
        throw new PatchException(sb.toString());
    }
    if (!simulate) {
        // bundle -> old location of the bundle to downgrade from
        final Map<Bundle, String> toUpdate = new HashMap<Bundle, String>();
        for (BundleUpdate update : result.getBundleUpdates()) {
            Version v = Version.parseVersion(update.getNewVersion() == null ? update.getPreviousVersion() : update.getNewVersion());
            for (Bundle bundle : allBundles) {
                if (bundle.getSymbolicName() == null || update.getSymbolicName() == null) {
                    continue;
                }
                if (stripSymbolicName(bundle.getSymbolicName()).equals(stripSymbolicName(update.getSymbolicName())) && bundle.getVersion().equals(v)) {
                    toUpdate.put(bundle, update.getPreviousLocation());
                }
            }
        }
        final boolean isStandaloneChild = patchManagement.isStandaloneChild();
        patchManagement.rollback(patch.getPatchData());
        Executors.newSingleThreadExecutor().execute(() -> {
            try {
                applyChanges(toUpdate);
                for (String featureOverride : result.getFeatureOverrides()) {
                    System.out.println("removing overriden feature: " + featureOverride);
                }
                if (result.getFeatureOverrides().size() > 0) {
                    System.out.println("refreshing features");
                    featuresService.refreshFeatures(EnumSet.noneOf(FeaturesService.Option.class));
                }
            } catch (Exception e) {
                throw new PatchException("Unable to rollback patch " + patch.getPatchData().getId() + ": " + e.getMessage(), e);
            }
            try {
                List<String> bases = patch.getResult().getKarafBases();
                bases.removeIf(s -> s.startsWith(System.getProperty("karaf.name")));
                patch.getResult().store();
                if (patch.getResult().getKarafBases().size() == 0) {
                    File file = new File(patchDir, result.getPatchData().getId() + ".patch.result");
                    file.delete();
                    patch.setResult(null);
                }
                if (patchManagement.isStandaloneChild()) {
                    File file = new File(patchDir, result.getPatchData().getId() + "." + System.getProperty("karaf.name") + ".patch.result");
                    if (file.isFile()) {
                        file.delete();
                    }
                }
            } catch (Exception e) {
                LOG.warn("Problem updating metadata for patch \"" + patch.getPatchData().getId() + "\": " + e.getMessage());
            }
        });
    }
}
Also used : HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) Bundle(org.osgi.framework.Bundle) ArrayList(java.util.ArrayList) URISyntaxException(java.net.URISyntaxException) PatchException(org.jboss.fuse.patch.management.PatchException) BundleException(org.osgi.framework.BundleException) IOException(java.io.IOException) Version(org.osgi.framework.Version) PatchResult(org.jboss.fuse.patch.management.PatchResult) PatchException(org.jboss.fuse.patch.management.PatchException) File(java.io.File) BundleUpdate(org.jboss.fuse.patch.management.BundleUpdate)

Example 22 with PatchException

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

the class PatchServiceImpl method checkStandaloneChild.

/**
 * Check if this is installation in @{link {@link org.jboss.fuse.patch.management.EnvType#STANDALONE_CHILD}}
 * - in this case the patch has to be installed in root first
 * @param patches
 */
private void checkStandaloneChild(Collection<Patch> patches) {
    if (patchManagement.isStandaloneChild()) {
        for (Patch patch : patches) {
            if (patch.getResult() == null) {
                throw new PatchException(String.format("Patch '%s' should be installed in parent container first", patch.getPatchData().getId()));
            } else {
                List<String> bases = patch.getResult().getKarafBases();
                boolean isInstalledInRoot = false;
                for (String base : bases) {
                    String[] coords = base.split("\\s*\\|\\s*");
                    if (coords.length == 2 && coords[1].trim().equals(System.getProperty("karaf.home"))) {
                        isInstalledInRoot = true;
                    }
                }
                if (!isInstalledInRoot) {
                    throw new PatchException(String.format("Patch '%s' should be installed in parent container first", patch.getPatchData().getId()));
                }
            }
        }
    }
}
Also used : PatchException(org.jboss.fuse.patch.management.PatchException) Patch(org.jboss.fuse.patch.management.Patch)

Example 23 with PatchException

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

the class PatchServiceImpl method download.

@Override
public Iterable<Patch> download(URL url) {
    if ("file".equals(url.getProtocol())) {
        // ENTESB-4992: prevent adding non existing files or directories
        try {
            if (!new File(url.toURI()).isFile()) {
                throw new PatchException("Path " + url.getPath() + " doesn't exist or is not a file");
            }
        } catch (URISyntaxException e) {
            throw new PatchException(e.getMessage(), e);
        }
    }
    try {
        List<PatchData> patchesData = patchManagement.fetchPatches(url);
        List<Patch> patches = new ArrayList<>(patchesData.size());
        for (PatchData patchData : patchesData) {
            Patch patch = patchManagement.trackPatch(patchData);
            patches.add(patch);
        }
        return patches;
    } catch (PatchException e) {
        throw e;
    } catch (Exception e) {
        throw new PatchException("Unable to download patch from url " + url, e);
    }
}
Also used : PatchData(org.jboss.fuse.patch.management.PatchData) ArrayList(java.util.ArrayList) PatchException(org.jboss.fuse.patch.management.PatchException) URISyntaxException(java.net.URISyntaxException) File(java.io.File) Patch(org.jboss.fuse.patch.management.Patch) URISyntaxException(java.net.URISyntaxException) PatchException(org.jboss.fuse.patch.management.PatchException) BundleException(org.osgi.framework.BundleException) IOException(java.io.IOException)

Example 24 with PatchException

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

the class PatchServiceImpl 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;
                        Version 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);
                }
            }
        }
    }
}
Also used : HashMap(java.util.HashMap) LinkedHashMap(java.util.LinkedHashMap) URI(java.net.URI) Feature(org.apache.karaf.features.Feature) LinkedList(java.util.LinkedList) URISyntaxException(java.net.URISyntaxException) PatchException(org.jboss.fuse.patch.management.PatchException) BundleException(org.osgi.framework.BundleException) IOException(java.io.IOException) Repository(org.apache.karaf.features.Repository) Version(org.osgi.framework.Version) PatchException(org.jboss.fuse.patch.management.PatchException) HashSet(java.util.HashSet) LinkedHashSet(java.util.LinkedHashSet) FeatureUpdate(org.jboss.fuse.patch.management.FeatureUpdate)

Example 25 with PatchException

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

the class PatchServiceImplTest method testCheckPrerequisitesNotInstalled.

@Test
public void testCheckPrerequisitesNotInstalled() throws IOException {
    PatchServiceImpl service = createMockServiceImpl(getDirectoryForResource("prereq/patch2.patch"));
    Patch patch = service.getPatch("patch2");
    assertNotNull(patch);
    try {
        service.checkPrerequisites(patch);
        fail("Patch will prerequisites that are not yet installed should not pass check");
    } catch (PatchException e) {
        assertTrue(e.getMessage().toLowerCase().contains("required patch 'prereq2' is not installed"));
    }
}
Also used : PatchException(org.jboss.fuse.patch.management.PatchException) Patch(org.jboss.fuse.patch.management.Patch) Test(org.junit.Test)

Aggregations

PatchException (org.jboss.fuse.patch.management.PatchException)25 IOException (java.io.IOException)14 Patch (org.jboss.fuse.patch.management.Patch)14 File (java.io.File)12 ZipFile (org.apache.commons.compress.archivers.zip.ZipFile)8 Git (org.eclipse.jgit.api.Git)7 GitAPIException (org.eclipse.jgit.api.errors.GitAPIException)7 ArrayList (java.util.ArrayList)6 HashMap (java.util.HashMap)6 LinkedHashMap (java.util.LinkedHashMap)6 LinkedList (java.util.LinkedList)6 URISyntaxException (java.net.URISyntaxException)5 RevCommit (org.eclipse.jgit.revwalk.RevCommit)5 RevWalk (org.eclipse.jgit.revwalk.RevWalk)5 BundleException (org.osgi.framework.BundleException)5 Map (java.util.Map)4 RevTag (org.eclipse.jgit.revwalk.RevTag)4 ManagedPatch (org.jboss.fuse.patch.management.ManagedPatch)4 LinkedHashSet (java.util.LinkedHashSet)3 ZipArchiveEntry (org.apache.commons.compress.archivers.zip.ZipArchiveEntry)3