use of io.fabric8.agent.service.State in project fabric8 by jboss-fuse.
the class FileBackupService method backupDataFiles.
/**
* Invoked just before Framework is restarted and data/cache directory is removed. We copy existing data
* directories for current bundles and record for which bundle$$version it is used.
* @param result used to create backup directories.
* @param pending
* @throws IOException
*/
@Override
public void backupDataFiles(PatchResult result, Pending pending) throws IOException {
Map<String, Bundle> bundlesWithData = new HashMap<>();
// bundle.getDataFile("xxx") creates data dir if it didn't exist - it's not what we want
String storageLocation = systemContext.getProperty("org.osgi.framework.storage");
if (storageLocation == null) {
Activator.log(LogService.LOG_INFO, "Can't determine \"org.osgi.framework.storage\" property value");
return;
}
File cacheDir = new File(storageLocation);
if (!cacheDir.isDirectory()) {
return;
}
for (Bundle b : systemContext.getBundles()) {
if (b.getSymbolicName() != null) {
String sn = Utils.stripSymbolicName(b.getSymbolicName());
if ("org.apache.karaf.features.core".equals(sn)) {
// we start with fresh features service state
continue;
}
// a bit of knowledge of how Felix works below...
File dataDir = new File(cacheDir, "bundle" + b.getBundleId() + "/data");
if (dataDir.isDirectory()) {
String key = String.format("%s$$%s", sn, b.getVersion().toString());
bundlesWithData.put(key, b);
}
}
}
// this property file will be used to map full symbolicName$$version to a location where bundle data
// is stored - the data must be restored both during R patch installation and rollback
Properties properties = new Properties();
String dirName = result.getPatchData().getId() + ".datafiles";
if (result.getParent() != null) {
dirName = result.getPatchData().getId() + "." + System.getProperty("karaf.name") + ".datafiles";
}
File dataBackupDir = new File(result.getPatchData().getPatchLocation(), dirName);
String prefix = pending == Pending.ROLLUP_INSTALLATION ? "install" : "rollback";
for (BundleUpdate update : result.getBundleUpdates()) {
// same update for both updated and reinstalled bundle
String key = String.format("%s$$%s", update.getSymbolicName(), pending == Pending.ROLLUP_INSTALLATION ? update.getPreviousVersion() : (update.getNewVersion() == null ? update.getPreviousVersion() : update.getNewVersion()));
if (bundlesWithData.containsKey(key)) {
File dataFileBackupDir = new File(dataBackupDir, prefix + "/" + key + "/data");
dataFileBackupDir.mkdirs();
final Bundle b = bundlesWithData.get(key);
FileUtils.copyDirectory(b.getDataFile(""), dataFileBackupDir, new FileFilter() {
@Override
public boolean accept(File pathname) {
return pathname.isDirectory() || !b.getSymbolicName().equals("org.apache.felix.configadmin") || pathname.getName().endsWith(".config");
}
});
properties.setProperty(key, key);
properties.setProperty(String.format("%s$$%s", update.getSymbolicName(), update.getPreviousVersion()), key);
if (update.getNewVersion() != null) {
properties.setProperty(String.format("%s$$%s", update.getSymbolicName(), update.getNewVersion()), key);
}
}
}
FileOutputStream propsFile = new FileOutputStream(new File(dataBackupDir, "backup-" + prefix + ".properties"));
properties.store(propsFile, "Data files to restore after \"" + result.getPatchData().getId() + "\" " + (pending == Pending.ROLLUP_INSTALLATION ? "installation" : "rollback"));
propsFile.close();
}
use of io.fabric8.agent.service.State in project fabric8 by jboss-fuse.
the class FabricPatchServiceImpl method install.
@Override
public PatchResult install(final Patch patch, boolean simulation, final String versionId, boolean upload, final String username, final String password, final ProfileUpdateStrategy strategy) throws IOException {
// we start from the same state as in standalone mode - after successful patch:add
// we have other things to do in fabric env however:
// 1. check prerequisites
// 2. we don't care about current state of framework - it'll be managed by fabric-agent and we don't
// necessary install a patch for this container we're in
// 3. we don't do patchManagement.beginInstallation / patchManagement.commitInstallation here
// this will be done later - after updated fabric-agent is started
// 4. we don't have to analyze bundles/features/repositories updates - these will be handled simply by
// updating profiles in specified version
PatchKind kind = patch.getPatchData().isRollupPatch() ? PatchKind.ROLLUP : PatchKind.NON_ROLLUP;
if (kind == PatchKind.NON_ROLLUP) {
throw new UnsupportedOperationException("patch:fabric-install should be used for Rollup patches only");
}
String currentContainersVersionId = fabricService.getCurrentContainer().getVersionId();
if (!simulation && versionId.equals(currentContainersVersionId)) {
throw new UnsupportedOperationException("Can't install Rollup patch in current version. Please install" + " this patch in new version and then upgrade existing container(s)");
}
fabricService.adapt(ProfileService.class).getRequiredVersion(versionId);
// just a list of new bundle locations - in fabric the updatable version depends on the moment we
// apply the new version to existing containers.
List<BundleUpdate> bundleUpdatesInThisPatch = bundleUpdatesInPatch(patch);
Presentation.displayBundleUpdates(bundleUpdatesInThisPatch, true);
PatchResult result = new PatchResult(patch.getPatchData(), simulation, System.currentTimeMillis(), bundleUpdatesInThisPatch, null);
if (!simulation) {
// update profile definitions stored in Git. We don't update ${karaf.home}/fabric, becuase it is used
// only once - when importing profiles during fabric:create.
// when fabric is already available, we have to update (Git) repository information
GitOperation operation = new GitOperation() {
@Override
public Object call(Git git, GitContext context) throws Exception {
// we can't pass git reference to patch-management
// because patch-management private-packages git library
// but we can leverage the write lock we have
GitHelpers.checkoutBranch(git, versionId);
// let's get back in history to the point before user changes (profile-edits), but not earlier
// than last R patch
String patchBranch = patchManagement.findLatestPatchRevision(git.getRepository().getDirectory(), versionId);
// now install profiles from patch just like there were no user changes
patchManagement.installProfiles(git.getRepository().getDirectory(), versionId, patch, strategy);
// and finally we have to merge user and patch changes to profiles.
patchManagement.mergeProfileChanges(patch, git.getRepository().getDirectory(), versionId, patchBranch);
context.commitMessage("Installing rollup patch \"" + patch.getPatchData().getId() + "\"");
return null;
}
};
gitDataStore.gitOperation(new GitContext().requireCommit().setRequirePush(true), operation, null);
if (upload) {
PatchManagement.UploadCallback callback = new PatchManagement.UploadCallback() {
@Override
public void doWithUrlConnection(URLConnection connection) throws ProtocolException {
if (connection instanceof HttpURLConnection) {
((HttpURLConnection) connection).setRequestMethod("PUT");
}
if (username != null && password != null) {
connection.setRequestProperty("Authorization", "Basic " + Base64Encoder.encode(username + ":" + password));
}
}
};
patchManagement.uploadPatchArtifacts(patch.getPatchData(), fabricService.getMavenRepoUploadURI(), callback);
}
}
return result;
}
use of io.fabric8.agent.service.State in project fabric8 by jboss-fuse.
the class AbstractManagedContainer method create.
@Override
public final synchronized void create(T configuration) throws LifecycleException {
if (state != null)
throw new IllegalStateException("Cannot create container in state: " + state);
this.configuration = configuration;
// [TODO] [FABRIC-929] No connector available to access repository jboss-public-repository-group
// Remove this hack. It shouldbe possible to use the shrinkwrap maven resolver
boolean useShrinkwrap = System.getProperty("shrinkwrap.resolver") != null;
for (MavenCoordinates artefact : configuration.getMavenCoordinates()) {
File zipfile = useShrinkwrap ? shrinkwrapResolve(artefact) : localResolve(artefact);
GenericArchive archive = ShrinkWrap.createFromZipFile(GenericArchive.class, zipfile);
ExplodedExporter exporter = archive.as(ExplodedExporter.class);
File targetdir = configuration.getTargetDirectory();
if (!targetdir.isDirectory() && !targetdir.mkdirs())
throw new IllegalStateException("Cannot create target dir: " + targetdir);
if (containerHome == null) {
exporter.exportExploded(targetdir, "");
File[] childDirs = targetdir.listFiles();
if (childDirs.length != 1)
throw new IllegalStateException("Expected one child directory, but was: " + Arrays.asList(childDirs));
containerHome = childDirs[0];
} else {
exporter.exportExploded(containerHome, "");
}
}
state = State.CREATED;
try {
doConfigure(configuration);
} catch (Exception ex) {
throw new LifecycleException("Cannot configure container", ex);
}
}
use of io.fabric8.agent.service.State in project fabric8 by jboss-fuse.
the class Agent method provision.
public void provision(Map<String, Feature> allFeatures, Set<String> features, Set<String> bundles, Set<String> reqs, Set<String> overrides, Set<String> optionals, Map<String, Map<VersionRange, Map<String, String>>> metadata) throws Exception {
Callable<Map<String, Resource>> res = loadResources(manager, metadata, optionals);
// TODO: requirements should be able to be assigned to a region
Map<String, Set<String>> requirements = new HashMap<>();
for (String feature : features) {
addToMapSet(requirements, ROOT_REGION, "feature:" + feature);
}
for (String bundle : bundles) {
addToMapSet(requirements, ROOT_REGION, "bundle:" + bundle);
}
for (String req : reqs) {
addToMapSet(requirements, ROOT_REGION, "req:" + req);
}
Deployer.DeploymentRequest request = new Deployer.DeploymentRequest();
request.updateSnaphots = updateSnaphots;
request.bundleUpdateRange = bundleUpdateRange;
request.featureResolutionRange = featureResolutionRange;
request.globalRepository = new StaticRepository(res.call().values());
request.overrides = overrides;
request.requirements = requirements;
request.stateChanges = Collections.emptyMap();
request.options = options;
request.metadata = metadata;
request.bundleStartTimeout = bundleStartTimeout;
Deployer.DeploymentState dstate = new Deployer.DeploymentState();
// Service bundle
dstate.serviceBundle = serviceBundle;
// Start level
FrameworkStartLevel fsl = systemBundleContext.getBundle().adapt(FrameworkStartLevel.class);
dstate.initialBundleStartLevel = fsl.getInitialBundleStartLevel();
dstate.currentStartLevel = fsl.getStartLevel();
// Bundles
dstate.bundles = new HashMap<>();
for (Bundle bundle : systemBundleContext.getBundles()) {
dstate.bundles.put(bundle.getBundleId(), bundle);
}
// Features
dstate.features = allFeatures;
// Region -> bundles mapping
// Region -> policy mapping
dstate.bundlesPerRegion = new HashMap<>();
dstate.filtersPerRegion = new HashMap<>();
if (digraph == null) {
for (Long id : dstate.bundles.keySet()) {
addToMapSet(dstate.bundlesPerRegion, ROOT_REGION, id);
}
} else {
RegionDigraph clone = digraph.copy();
for (Region region : clone.getRegions()) {
// Get bundles
dstate.bundlesPerRegion.put(region.getName(), new HashSet<>(region.getBundleIds()));
// Get policies
Map<String, Map<String, Set<String>>> edges = new HashMap<>();
for (RegionDigraph.FilteredRegion fr : clone.getEdges(region)) {
Map<String, Set<String>> policy = new HashMap<>();
Map<String, Collection<String>> current = fr.getFilter().getSharingPolicy();
for (String ns : current.keySet()) {
for (String f : current.get(ns)) {
addToMapSet(policy, ns, f);
}
}
edges.put(fr.getRegion().getName(), policy);
}
dstate.filtersPerRegion.put(region.getName(), edges);
}
}
final State state = new State();
try {
storage.load(state);
} catch (IOException e) {
LOGGER.warn("Error loading agent state", e);
}
if (state.managedBundles.isEmpty()) {
for (Bundle b : systemBundleContext.getBundles()) {
if (b.getBundleId() != 0) {
addToMapSet(state.managedBundles, ROOT_REGION, b.getBundleId());
}
}
}
// corresponding jar url and use that one to compute the checksum of the bundle.
for (Map.Entry<Long, Bundle> entry : dstate.bundles.entrySet()) {
long id = entry.getKey();
Bundle bundle = entry.getValue();
if (id > 0 && isUpdateable(bundle) && !state.bundleChecksums.containsKey(id)) {
try {
URL url = bundle.getResource("META-INF/MANIFEST.MF");
URLConnection con = url.openConnection();
Method method = con.getClass().getDeclaredMethod("getLocalURL");
method.setAccessible(true);
String jarUrl = ((URL) method.invoke(con)).toExternalForm();
if (jarUrl.startsWith("jar:")) {
String jar = jarUrl.substring("jar:".length(), jarUrl.indexOf("!/"));
jar = new URL(jar).getFile();
long checksum = ChecksumUtils.checksumFile(new File(jar));
state.bundleChecksums.put(id, checksum);
}
} catch (Throwable t) {
LOGGER.debug("Error calculating checksum for bundle: %s", bundle, t);
}
}
}
dstate.state = state;
Set<String> prereqs = new HashSet<>();
while (true) {
try {
Deployer.DeployCallback callback = new BaseDeployCallback() {
@Override
public void phase(String message) {
Agent.this.updateStatus(message);
}
@Override
public void saveState(State newState) {
state.replace(newState);
try {
Agent.this.saveState(newState);
} catch (IOException e) {
LOGGER.warn("Error storing agent state", e);
}
}
@Override
public void provisionList(Set<Resource> resources) {
Agent.this.provisionList(resources);
}
@Override
public void restoreConfigAdminIfNeeded() {
if (configInstaller != null) {
configInstaller.restoreConfigAdminIfNeeded();
}
}
@Override
public boolean done(boolean agentStarted, List<String> urls) {
return Agent.this.done(agentStarted, urls);
}
};
// FABRIC-790, FABRIC-981 - wait for ProfileUrlHandler before attempting to load bundles (in subsystem.resolve())
// (which may be the case with bundle.xxx=blueprint:profile:xxx URLs in io.fabric8.agent PID)
// https://developer.jboss.org/message/920681 - 30 seconds is too low sometimes
// there was "url.handler.timeouts" option for agent, but it was removed during migration to karaf 4.x resolver
// LOGGER.debug("Waiting for ProfileUrlHandler");
// awaitService(URLStreamHandlerService.class, "(url.handler.protocol=profile)", 30, TimeUnit.SECONDS);
// LOGGER.debug("Waiting for ProfileUrlHandler finished");
Deployer deployer = new Deployer(manager, callback);
deployer.setDeploymentAgentId(deploymentAgentId);
deployer.deploy(dstate, request);
break;
} catch (Deployer.PartialDeploymentException e) {
if (!prereqs.containsAll(e.getMissing())) {
prereqs.addAll(e.getMissing());
} else {
throw new Exception("Deployment aborted due to loop in missing prerequisites: " + e.getMissing());
}
}
}
}
use of io.fabric8.agent.service.State in project fabric8 by jboss-fuse.
the class OpenShiftDeployAgent method groupEvent.
@Override
public void groupEvent(Group<ControllerNode> group, GroupEvent event) {
if (isValid()) {
if (group.isMaster()) {
LOGGER.info("OpenShiftDeployAgent is the master");
} else {
LOGGER.info("OpenShiftDeployAgent is not the master");
}
try {
DataStore dataStore = null;
if (fabricService != null) {
dataStore = fabricService.get().adapt(DataStore.class);
} else {
LOGGER.warn("No fabricService yet!");
}
if (group.isMaster()) {
ControllerNode state = createState();
group.update(state);
}
if (dataStore != null) {
if (group.isMaster()) {
dataStore.trackConfiguration(runnable);
onConfigurationChanged();
} else {
dataStore.untrackConfiguration(runnable);
}
}
} catch (IllegalStateException e) {
// Ignore
}
}
}
Aggregations