Search in sources :

Example 26 with State

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();
}
Also used : HashMap(java.util.HashMap) Bundle(org.osgi.framework.Bundle) FileOutputStream(java.io.FileOutputStream) Properties(java.util.Properties) FileFilter(java.io.FileFilter) File(java.io.File) BundleUpdate(io.fabric8.patch.management.BundleUpdate)

Example 27 with State

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;
}
Also used : PatchKind(io.fabric8.patch.management.PatchKind) HttpURLConnection(java.net.HttpURLConnection) URLConnection(java.net.URLConnection) ProfileService(io.fabric8.api.ProfileService) GitOperation(io.fabric8.git.internal.GitOperation) Git(org.eclipse.jgit.api.Git) HttpURLConnection(java.net.HttpURLConnection) GitContext(io.fabric8.api.GitContext) PatchManagement(io.fabric8.patch.management.PatchManagement) PatchResult(io.fabric8.patch.management.PatchResult) BundleUpdate(io.fabric8.patch.management.BundleUpdate)

Example 28 with State

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);
    }
}
Also used : MavenCoordinates(io.fabric8.api.gravia.MavenCoordinates) LifecycleException(io.fabric8.runtime.container.LifecycleException) GenericArchive(org.jboss.shrinkwrap.api.GenericArchive) ExplodedExporter(org.jboss.shrinkwrap.api.exporter.ExplodedExporter) File(java.io.File) LifecycleException(io.fabric8.runtime.container.LifecycleException) IOException(java.io.IOException)

Example 29 with State

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());
            }
        }
    }
}
Also used : EnumSet(java.util.EnumSet) Set(java.util.Set) MapUtils.addToMapSet(io.fabric8.agent.internal.MapUtils.addToMapSet) HashSet(java.util.HashSet) HashMap(java.util.HashMap) URL(java.net.URL) List(java.util.List) HashSet(java.util.HashSet) RegionDigraph(org.eclipse.equinox.region.RegionDigraph) Bundle(org.osgi.framework.Bundle) IOException(java.io.IOException) Method(java.lang.reflect.Method) FrameworkStartLevel(org.osgi.framework.startlevel.FrameworkStartLevel) URLConnection(java.net.URLConnection) BundleException(org.osgi.framework.BundleException) InvalidSyntaxException(org.osgi.framework.InvalidSyntaxException) MalformedURLException(java.net.MalformedURLException) IOException(java.io.IOException) MultiException(io.fabric8.common.util.MultiException) Region(org.eclipse.equinox.region.Region) Collection(java.util.Collection) Map(java.util.Map) HashMap(java.util.HashMap) File(java.io.File) StaticRepository(io.fabric8.agent.repository.StaticRepository)

Example 30 with State

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
        }
    }
}
Also used : DataStore(io.fabric8.api.DataStore)

Aggregations

IOException (java.io.IOException)15 File (java.io.File)11 Test (org.junit.Test)10 ArrayList (java.util.ArrayList)7 HashMap (java.util.HashMap)7 Bundle (org.osgi.framework.Bundle)6 BundleUpdate (io.fabric8.patch.management.BundleUpdate)5 BundleException (org.osgi.framework.BundleException)5 BufferState (io.fabric8.dosgi.io.ProtocolCodec.BufferState)4 ByteBuffer (java.nio.ByteBuffer)4 Buffer (org.fusesource.hawtbuf.Buffer)4 Downloader (io.fabric8.agent.download.Downloader)3 Container (io.fabric8.kubernetes.api.model.Container)3 IntOrString (io.fabric8.kubernetes.api.model.IntOrString)3 URI (java.net.URI)3 URISyntaxException (java.net.URISyntaxException)3 LinkedHashMap (java.util.LinkedHashMap)3 List (java.util.List)3 Map (java.util.Map)3 DownloadCallback (io.fabric8.agent.download.DownloadCallback)2