All Downloads are FREE. Search and download functionalities are using the official Maven repository.

actors.DockerPackageRefresher Maven / Gradle / Ivy

The newest version!
/**
 * Copyright 2015 Groupon.com
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package actors;

import akka.actor.AbstractActor;
import akka.pattern.PatternsCS;
import client.DockerPackageClient;
import client.DockerPackageClient.PackageListResponse;
import com.arpnetworking.steno.Logger;
import com.arpnetworking.steno.LoggerFactory;
import com.google.inject.Inject;
import com.google.inject.name.Named;
import io.ebean.Ebean;
import io.ebean.Transaction;
import models.Package;
import models.PackageVersion;
import scala.concurrent.duration.FiniteDuration;

import java.util.List;
import java.util.Map;
import java.util.concurrent.CompletionStage;
import java.util.concurrent.TimeUnit;
import javax.inject.Singleton;

/**
 * Refreshes docker packages from a docker registry.
 *
 * @author Matthew Hayter (mhayter at groupon dot com)
 */
@Singleton
public class DockerPackageRefresher extends AbstractActor {

    /**
     * Public constructor.
     *
     * @param dockerClient The client to use to interact with the docker registry
     * @param registryName The string to be put in the Package model's 'repository' field
     */
    @Inject
    public DockerPackageRefresher(final DockerPackageClient dockerClient, @Named("DockerRegistryName") final String registryName) {
        context().system().scheduler().schedule(
                FiniteDuration.apply(3, TimeUnit.SECONDS),
                FiniteDuration.apply(3, TimeUnit.HOURS),
                self(),
                new RefreshPackagesMessage(),
                context().dispatcher(),
                self());
        _dockerPackageClient = dockerClient;
        _registryName = registryName;
    }

    @Override
    public Receive createReceive() {
        return receiveBuilder()
                .match(RefreshPackagesMessage.class, message -> {
                    if (_refreshState == RefreshStates.READY) {
                        fetchPackagesAndSendMessage();
                    } else {
                        _refreshState = RefreshStates.QUEUED;
                    }
                })
                .match(PackageListMessage.class, message -> {
                    final DockerPackageClient.PackageListResponse list = message.getList();
                    final Map> packages = list.getPackages();
                    persistImagesToPackageVersions(packages);

                    if (_refreshState == RefreshStates.QUEUED) {
                        self().tell(new RefreshPackagesMessage(), self());
                    }
                    _refreshState = RefreshStates.READY;

                })
                .build();
    }

    private void fetchPackagesAndSendMessage() {
        _refreshState = RefreshStates.RUNNING;
        final CompletionStage imagesListPromise =
                _dockerPackageClient
                        .getAllPackages()
                        .thenApply(PackageListMessage::new);
        PatternsCS.pipe(imagesListPromise, context().dispatcher()).to(self(), self());
    }

    private void persistImagesToPackageVersions(final Map> repoToImageMap) {

        repoToImageMap.forEach((repoName, imageMetadataList) -> {
            try (Transaction transaction = Ebean.beginTransaction()) {
                Package aPackage = Package.getByName(repoName);
                if (aPackage == null) {
                    aPackage = new Package();
                    aPackage.setName(repoName);
                    aPackage.save();
                }

                for (final DockerPackageClient.ImageMetadata imageMetadata : imageMetadataList) {
                    PackageVersion packageVersion = PackageVersion.getByRepositoryPackageAndVersion(_registryName,
                                                                                                    aPackage,
                                                                                                    imageMetadata.getId());

                    if (packageVersion == null) {
                        packageVersion = new PackageVersion();
                        packageVersion.setType(TYPE_FOR_PACKAGES);
                        packageVersion.setRepository(_registryName);
                        packageVersion.setVersion(imageMetadata.getId());
                        packageVersion.setPkg(aPackage);
                    }
                    // TODO(mhayter): format the description nicely [Artemis-?]

                    // Take the first 254 characters of description
                    final String description = imageMetadata.getTags().toString();
                    packageVersion.setDescription(description.substring(0, Math.min(description.length(), 254)));

                    packageVersion.save();
                }
                transaction.commit();
            }
        });
    }

    private RefreshStates _refreshState = RefreshStates.READY;
    private final DockerPackageClient _dockerPackageClient;
    private final String _registryName;

    private static final String TYPE_FOR_PACKAGES = "docker";
    private static final Logger LOGGER = LoggerFactory.getLogger(DockerPackageRefresher.class);

    private enum RefreshStates {
        READY,
        QUEUED,
        RUNNING
    }

    private static class PackageListMessage {
        private final PackageListResponse _list;

        PackageListMessage(final PackageListResponse list) {
            _list = list;
        }

        public PackageListResponse getList() {
            return _list;
        }
    }

    private static class RefreshPackagesMessage {}
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy