use of org.jboss.fuse.patch.management.PatchData in project fuse-karaf by jboss-fuse.
the class GitPatchManagementServiceImpl method fetchPatches.
@Override
public List<PatchData> fetchPatches(URL url) throws PatchException {
try {
List<PatchData> patches = new ArrayList<>(1);
File patchFile = new File(patchesDir, Long.toString(System.currentTimeMillis()) + ".patch.tmp");
InputStream input = url.openStream();
FileOutputStream output = new FileOutputStream(patchFile);
ZipFile zf = null;
try {
IOUtils.copy(input, output);
} finally {
Utils.closeQuietly(input);
Utils.closeQuietly(output);
}
try {
zf = new ZipFile(patchFile);
} catch (IOException ignored) {
if (!FilenameUtils.getExtension(url.getFile()).equals("patch")) {
throw new PatchException("Patch should be ZIP file or *.patch descriptor");
}
}
// patchFile may "be" a patch descriptor or be a ZIP file containing descriptor
PatchData patchData = null;
// in case patch ZIP file has no descriptor, we'll "generate" patch data on the fly
// no descriptor -> assume we have rollup patch or even full, new distribution
PatchData fallbackPatchData = new PatchData(FilenameUtils.getBaseName(url.getPath()));
fallbackPatchData.setGenerated(true);
fallbackPatchData.setRollupPatch(true);
fallbackPatchData.setPatchDirectory(new File(patchesDir, fallbackPatchData.getId()));
fallbackPatchData.setPatchLocation(patchesDir);
if (zf != null) {
File systemRepo = getSystemRepository(karafHome, systemContext);
try {
List<ZipArchiveEntry> otherResources = new LinkedList<>();
boolean skipRootDir = false;
for (Enumeration<ZipArchiveEntry> e = zf.getEntries(); e.hasMoreElements(); ) {
ZipArchiveEntry entry = e.nextElement();
if (!skipRootDir && entry.isDirectory() && entry.getName().startsWith("fuse-karaf-")) {
skipRootDir = true;
}
if (entry.isDirectory() || entry.isUnixSymlink()) {
continue;
}
String name = entry.getName();
if (skipRootDir) {
name = name.substring(name.indexOf('/') + 1);
}
if (!name.contains("/") && name.endsWith(".patch")) {
// patch descriptor in ZIP's root directory
if (patchData == null) {
// load data from patch descriptor inside ZIP. This may or may not be a rollup
// patch
File target = new File(patchesDir, name);
extractZipEntry(zf, entry, target);
patchData = loadPatchData(target);
// ENTESB-4600: try checking the target version of the patch
Version version = Utils.findVersionInName(patchData.getId());
if (version.getMajor() == 6 && version.getMinor() == 1) {
throw new PatchException("Can't install patch \"" + patchData.getId() + "\", it is released for version 6.x of the product");
}
patchData.setGenerated(false);
File targetDirForPatchResources = new File(patchesDir, patchData.getId());
patchData.setPatchDirectory(targetDirForPatchResources);
patchData.setPatchLocation(patchesDir);
target.renameTo(new File(patchesDir, patchData.getId() + ".patch"));
patches.add(patchData);
} else {
throw new PatchException(String.format("Multiple patch descriptors: already have patch %s and now encountered entry %s", patchData.getId(), name));
}
} else {
File target = null;
String relativeName = null;
if (name.startsWith("system/")) {
// copy to ${karaf.default.repository}
relativeName = name.substring("system/".length());
target = new File(systemRepo, relativeName);
} else if (name.startsWith("repository/")) {
// copy to ${karaf.default.repository}
relativeName = name.substring("repository/".length());
target = new File(systemRepo, relativeName);
} else {
// other files that should be applied to ${karaf.home} when the patch is installed
otherResources.add(entry);
}
if (target != null) {
// we unzip to system repository
extractAndTrackZipEntry(fallbackPatchData, zf, entry, target, skipRootDir);
}
}
}
File targetDirForPatchResources = new File(patchesDir, patchData == null ? fallbackPatchData.getId() : patchData.getId());
// now copy non-maven resources (we should now know where to copy them)
for (ZipArchiveEntry entry : otherResources) {
String name = entry.getName();
if (skipRootDir) {
name = name.substring(name.indexOf('/'));
}
File target = new File(targetDirForPatchResources, name);
extractAndTrackZipEntry(fallbackPatchData, zf, entry, target, skipRootDir);
}
} finally {
if (zf != null) {
zf.close();
}
if (patchFile != null) {
patchFile.delete();
}
}
} else {
// If the file is not a zip/jar, assume it's a single patch file
patchData = loadPatchData(patchFile);
// no patch directory - no attached content, assuming only references to bundles
patchData.setPatchDirectory(null);
patchFile.renameTo(new File(patchesDir, patchData.getId() + ".patch"));
patches.add(patchData);
}
if (patches.size() == 0) {
// let's use generated patch descriptor
File generatedPatchDescriptor = new File(patchesDir, fallbackPatchData.getId() + ".patch");
FileOutputStream out = new FileOutputStream(generatedPatchDescriptor);
try {
fallbackPatchData.storeTo(out);
} finally {
Utils.closeQuietly(out);
}
patches.add(fallbackPatchData);
}
return patches;
} catch (IOException e) {
throw new PatchException("Unable to download patch from url " + url, e);
}
}
use of org.jboss.fuse.patch.management.PatchData in project fuse-karaf by jboss-fuse.
the class GitPatchManagementServiceImpl method gatherOverrides.
/**
* Returns list of bundle updates (maven coordinates) from HF/P patch that should be preserved during
* installation of R patch
* @param hfPatchId ID of patch that was detected to be HF patch installed previously (before R patch just being installed)
* @param patch R patch which is currently being installed
* @return an artificial {@link PatchData} with a list of maven URIs for bundles that are newer in previous P-patches than the ones in currently installed R-patch
*/
private PatchData gatherOverrides(String hfPatchId, Patch patch) {
Patch hf = loadPatch(new PatchDetailsRequest(hfPatchId));
List<String> bundles = new LinkedList<>();
Map<String, String> ranges = new LinkedHashMap<>();
if (hf != null && hf.getPatchData() != null) {
for (String bundle : hf.getPatchData().getBundles()) {
bundles.add(bundle);
String versionRange = hf.getPatchData().getVersionRange(bundle);
if (versionRange != null && !versionRange.trim().equals("")) {
ranges.put(bundle, versionRange);
}
}
// leave only these artifacts that are in newer version than in R patch being installed
if (patch != null && patch.getPatchData() != null) {
Map<String, Artifact> cache = new HashMap<>();
for (String bu : patch.getPatchData().getBundles()) {
Artifact rPatchArtifact = Utils.mvnurlToArtifact(bu, true);
if (rPatchArtifact != null) {
cache.put(String.format("%s:%s", rPatchArtifact.getGroupId(), rPatchArtifact.getArtifactId()), rPatchArtifact);
}
}
for (String bu : hf.getPatchData().getBundles()) {
Artifact hfPatchArtifact = Utils.mvnurlToArtifact(bu, true);
if (hfPatchArtifact != null) {
String key = String.format("%s:%s", hfPatchArtifact.getGroupId(), hfPatchArtifact.getArtifactId());
if (cache.containsKey(key)) {
Version hfVersion = Utils.getOsgiVersion(hfPatchArtifact.getVersion());
Version rVersion = Utils.getOsgiVersion(cache.get(key).getVersion());
if (rVersion.compareTo(hfVersion) >= 0) {
bundles.remove(bu);
ranges.remove(bu);
}
}
}
}
}
}
return new PatchData(null, null, bundles, null, ranges, null, null);
}
use of org.jboss.fuse.patch.management.PatchData 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);
}
}
use of org.jboss.fuse.patch.management.PatchData 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);
}
}
use of org.jboss.fuse.patch.management.PatchData in project fuse-karaf by jboss-fuse.
the class PatchServiceImplTest method testLoadWithoutRanges.
@Test
public void testLoadWithoutRanges() throws IOException, GitAPIException {
BundleContext bundleContext = mock(BundleContext.class);
ComponentContext componentContext = mock(ComponentContext.class);
Bundle sysBundle = mock(Bundle.class);
BundleContext sysBundleContext = mock(BundleContext.class);
Bundle bundle = mock(Bundle.class);
Bundle bundle2 = mock(Bundle.class);
FrameworkWiring wiring = mock(FrameworkWiring.class);
GitPatchRepository repository = mock(GitPatchRepository.class);
//
// Create a new service, download a patch
//
when(componentContext.getBundleContext()).thenReturn(bundleContext);
when(bundleContext.getBundle(0)).thenReturn(sysBundle);
when(sysBundle.getBundleContext()).thenReturn(sysBundleContext);
when(sysBundleContext.getProperty(PatchService.PATCH_LOCATION)).thenReturn(storage.toString());
when(repository.getManagedPatch(anyString())).thenReturn(null);
when(repository.findOrCreateMainGitRepository()).thenReturn(null);
when(sysBundleContext.getProperty("karaf.default.repository")).thenReturn("system");
when(sysBundleContext.getProperty("karaf.home")).thenReturn(karaf.getCanonicalPath());
when(sysBundleContext.getProperty("karaf.base")).thenReturn(karaf.getCanonicalPath());
when(sysBundleContext.getProperty("karaf.name")).thenReturn("root");
when(sysBundleContext.getProperty("karaf.instances")).thenReturn(karaf.getCanonicalPath() + "/instances");
when(sysBundleContext.getProperty("karaf.data")).thenReturn(karaf.getCanonicalPath() + "/data");
when(sysBundleContext.getProperty("karaf.etc")).thenReturn(karaf.getCanonicalPath() + "/etc");
PatchManagement pm = new GitPatchManagementServiceImpl(bundleContext);
((GitPatchManagementServiceImpl) pm).setGitPatchRepository(repository);
PatchServiceImpl service = new PatchServiceImpl();
setField(service, "patchManagement", pm);
service.activate(componentContext);
PatchData pd = PatchData.load(getClass().getClassLoader().getResourceAsStream("test1.patch"));
assertEquals(2, pd.getBundles().size());
assertTrue(pd.getRequirements().isEmpty());
}
Aggregations