com.eucalyptus.autoscaling.common.internal.instances.PersistenceAutoScalingInstances.java Source code

Java tutorial

Introduction

Here is the source code for com.eucalyptus.autoscaling.common.internal.instances.PersistenceAutoScalingInstances.java

Source

/*************************************************************************
 * Copyright 2009-2013 Eucalyptus Systems, Inc.
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see http://www.gnu.org/licenses/.
 *
 * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta
 * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need
 * additional information or have any questions.
 ************************************************************************/
package com.eucalyptus.autoscaling.common.internal.instances;

import static com.eucalyptus.autoscaling.common.AutoScalingMetadata.AutoScalingGroupMetadata;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import org.hibernate.criterion.Criterion;
import org.hibernate.criterion.Property;
import org.hibernate.criterion.Restrictions;
import com.eucalyptus.autoscaling.common.internal.metadata.AbstractOwnedPersistents;
import com.eucalyptus.autoscaling.common.internal.metadata.AutoScalingMetadataException;
import com.eucalyptus.autoscaling.common.internal.metadata.AutoScalingMetadataNotFoundException;
import com.eucalyptus.component.annotation.ComponentNamed;
import com.eucalyptus.util.Callback;
import com.eucalyptus.util.CollectionUtils;
import com.eucalyptus.auth.principal.OwnerFullName;
import com.google.common.base.Function;
import com.google.common.base.Functions;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.collect.Iterables;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 *
 */
@ComponentNamed
public class PersistenceAutoScalingInstances extends AutoScalingInstances {

    private final Logger logger = Logger.getLogger(PersistenceAutoScalingInstances.class);

    private PersistenceSupport persistenceSupport = new PersistenceSupport();

    @Override
    public <T> List<T> list(final OwnerFullName ownerFullName, final Predicate<? super AutoScalingInstance> filter,
            final Function<? super AutoScalingInstance, T> transform) throws AutoScalingMetadataException {
        return persistenceSupport.list(ownerFullName, filter, transform);
    }

    @Override
    public <T> List<T> listByGroup(final OwnerFullName ownerFullName, final String groupName,
            final Function<? super AutoScalingInstance, T> transform) throws AutoScalingMetadataException {
        final AutoScalingInstance example = AutoScalingInstance.withOwner(ownerFullName);
        example.setAutoScalingGroupName(groupName);
        return persistenceSupport.listByExample(example, Predicates.alwaysTrue(), transform);
    }

    @Override
    public <T> List<T> listByGroup(final AutoScalingGroupMetadata group,
            final Predicate<? super AutoScalingInstance> filter,
            final Function<? super AutoScalingInstance, T> transform) throws AutoScalingMetadataException {
        final AutoScalingInstance example = exampleForGroup(group);
        return persistenceSupport.listByExample(example, filter, transform);
    }

    @Override
    public <T> List<T> listByState(final LifecycleState lifecycleState, final ConfigurationState configurationState,
            final Function<? super AutoScalingInstance, T> transform) throws AutoScalingMetadataException {
        final AutoScalingInstance example = AutoScalingInstance.withStates(lifecycleState, configurationState);
        return persistenceSupport.listByExample(example, Predicates.and(lifecycleState, configurationState),
                transform);
    }

    @Override
    public <T> List<T> listUnhealthyByGroup(final AutoScalingGroupMetadata group,
            final Function<? super AutoScalingInstance, T> transform) throws AutoScalingMetadataException {
        final AutoScalingInstance example = exampleForGroup(group);
        example.setHealthStatus(HealthStatus.Unhealthy);
        return persistenceSupport.listByExample(example, Predicates.alwaysTrue(), transform);
    }

    @Override
    public <T> T lookup(final OwnerFullName ownerFullName, final String instanceId,
            final Function<? super AutoScalingInstance, T> transform) throws AutoScalingMetadataException {
        return persistenceSupport.lookupByExample(persistenceSupport.exampleWithName(ownerFullName, instanceId),
                ownerFullName, instanceId, Predicates.alwaysTrue(), transform);
    }

    @Override
    public void update(final OwnerFullName ownerFullName, final String instanceId,
            final Callback<AutoScalingInstance> instanceUpdateCallback) throws AutoScalingMetadataException {
        persistenceSupport.updateByExample(persistenceSupport.exampleWithName(ownerFullName, instanceId),
                ownerFullName, instanceId, instanceUpdateCallback);
    }

    @Override
    public void markMissingInstancesUnhealthy(final AutoScalingGroupMetadata group,
            final Collection<String> instanceIds) throws AutoScalingMetadataException {
        final AutoScalingInstance example = exampleForGroup(group);
        example.setHealthStatus(HealthStatus.Healthy);

        final List<AutoScalingInstance> instancesToMark = persistenceSupport.listByExample(example,
                LifecycleState.InService,
                instanceIds.isEmpty() ? Restrictions.conjunction()
                        : Restrictions.not(Property.forName("displayName").in(instanceIds)),
                Collections.<String, String>emptyMap(), Functions.<AutoScalingInstance>identity());

        for (final AutoScalingInstance instance : instancesToMark) {
            try {
                persistenceSupport.updateByExample(AutoScalingInstance.withUuid(instance.getNaturalId()),
                        group.getOwner(), instance.getInstanceId(), new Callback<AutoScalingInstance>() {
                            @Override
                            public void fire(final AutoScalingInstance instance) {
                                if (instance.healthStatusGracePeriodExpired()) {
                                    logger.info("Marking instance unhealthy: " + instance.getInstanceId());
                                    instance.setHealthStatus(HealthStatus.Unhealthy);
                                } else {
                                    logger.debug("Instance not healthy but within grace period: "
                                            + instance.getInstanceId());
                                }
                            }
                        });
            } catch (final AutoScalingMetadataNotFoundException e) {
                // removed, no need to mark unhealthy
            }
        }
    }

    @Override
    public void markExpiredPendingUnhealthy(final AutoScalingGroupMetadata group,
            final Collection<String> instanceIds, final long maxAge) throws AutoScalingMetadataException {
        final AutoScalingInstance example = exampleForGroup(group);
        example.setHealthStatus(HealthStatus.Healthy);

        final List<AutoScalingInstance> instancesToMark = instanceIds.isEmpty()
                ? Collections.<AutoScalingInstance>emptyList()
                : persistenceSupport.listByExample(example, LifecycleState.Pending,
                        Property.forName("displayName").in(instanceIds), Collections.<String, String>emptyMap(),
                        Functions.<AutoScalingInstance>identity());

        for (final AutoScalingInstance instance : instancesToMark) {
            try {
                persistenceSupport.updateByExample(AutoScalingInstance.withUuid(instance.getNaturalId()),
                        group.getOwner(), instance.getInstanceId(), new Callback<AutoScalingInstance>() {
                            @Override
                            public void fire(final AutoScalingInstance instance) {
                                if (instance.getCreationTimestamp().getTime() < maxAge) {
                                    logger.info("Marking pending instance unhealthy: " + instance.getInstanceId());
                                    instance.setHealthStatus(HealthStatus.Unhealthy);
                                } else {
                                    logger.debug("Not marking pending instance unhealthy (within timeout): "
                                            + instance.getInstanceId());
                                }
                            }
                        });
            } catch (final AutoScalingMetadataNotFoundException e) {
                // removed, no need to mark unhealthy
            }
        }
    }

    @Override
    public Set<String> verifyInstanceIds(final String accountNumber, final Collection<String> instanceIds)
            throws AutoScalingMetadataException {
        final Set<String> verifiedInstanceIds = Sets.newHashSet();

        if (!instanceIds.isEmpty()) {
            final AutoScalingInstance example = AutoScalingInstance.withOwner(accountNumber);
            final Criterion idCriterion = Property.forName("displayName").in(instanceIds);

            Iterables.addAll(verifiedInstanceIds, persistenceSupport.listByExample(example, Predicates.alwaysTrue(),
                    idCriterion, Collections.<String, String>emptyMap(), AutoScalingInstances.instanceId()));
        }

        return verifiedInstanceIds;
    }

    @Override
    public void transitionState(final AutoScalingGroupMetadata group, final LifecycleState from,
            final LifecycleState to, final Collection<String> instanceIds) throws AutoScalingMetadataException {
        final AutoScalingInstance example = exampleForGroup(group);
        example.setLifecycleState(from);
        updateInstances(example, from, from.transitionTo(to), instanceIds);
    }

    @Override
    public void transitionConfigurationState(final AutoScalingGroupMetadata group, final ConfigurationState from,
            final ConfigurationState to, final Collection<String> instanceIds) throws AutoScalingMetadataException {
        final AutoScalingInstance example = exampleForGroup(group);
        example.setConfigurationState(from);
        updateInstances(example, from, from.transitionTo(to), instanceIds);
    }

    @Override
    public int registrationFailure(final AutoScalingGroupMetadata group, final Collection<String> instanceIds)
            throws AutoScalingMetadataException {
        final AutoScalingInstance example = exampleForGroup(group);
        final Map<String, Integer> failureCountMap = Maps.newHashMap();
        updateInstances(example, Predicates.alwaysTrue(), new Predicate<AutoScalingInstance>() {
            @Override
            public boolean apply(final AutoScalingInstance instance) {
                failureCountMap.put(instance.getInstanceId(), instance.incrementRegistrationAttempts());
                return true;
            }
        }, instanceIds);
        return CollectionUtils.reduce(failureCountMap.values(), Integer.MAX_VALUE, CollectionUtils.min());
    }

    @Override
    public boolean delete(final OwnerFullName ownerFullName, final String instanceId)
            throws AutoScalingMetadataException {
        return !persistenceSupport.withRetries()
                .deleteByExample(persistenceSupport.exampleWithName(ownerFullName, instanceId)).isEmpty();
    }

    @Override
    public boolean deleteByGroup(final AutoScalingGroupMetadata group) throws AutoScalingMetadataException {
        final AutoScalingInstance example = exampleForGroup(group);
        return !persistenceSupport.withRetries().deleteByExample(example).isEmpty();
    }

    @Override
    public AutoScalingInstance save(final AutoScalingInstance autoScalingInstance)
            throws AutoScalingMetadataException {
        return persistenceSupport.save(autoScalingInstance);
    }

    private AutoScalingInstance exampleForGroup(final AutoScalingGroupMetadata group) {
        final AutoScalingInstance example = AutoScalingInstance.withOwner(group.getOwner());
        example.clearUserIdentity();
        example.setAutoScalingGroupName(group.getDisplayName());
        return example;
    }

    private void updateInstances(final AutoScalingInstance fromExample,
            final Predicate<? super AutoScalingInstance> fromPredicate,
            final Predicate<? super AutoScalingInstance> updatePredicate, final Collection<String> instanceIds)
            throws AutoScalingMetadataException {
        final AbstractOwnedPersistents.WorkCallback<Void> updateCallback = new AbstractOwnedPersistents.WorkCallback<Void>() {
            @Override
            public Void doWork() throws AutoScalingMetadataException {
                final List<AutoScalingInstance> instances = persistenceSupport.listByExample(fromExample,
                        fromPredicate, Property.forName("displayName").in(instanceIds),
                        Collections.<String, String>emptyMap(), Functions.<AutoScalingInstance>identity());
                CollectionUtils.each(instances, updatePredicate);
                return null;
            }
        };

        if (!instanceIds.isEmpty()) {
            persistenceSupport.transactionWithRetry(AutoScalingInstance.class, updateCallback);
        }
    }

    private static class PersistenceSupport extends AbstractOwnedPersistents<AutoScalingInstance> {
        private PersistenceSupport() {
            super("auto scaling instance");
        }

        @Override
        protected AutoScalingInstance exampleWithOwner(final OwnerFullName ownerFullName) {
            return AutoScalingInstance.withOwner(ownerFullName);
        }

        @Override
        protected AutoScalingInstance exampleWithName(final OwnerFullName ownerFullName, final String name) {
            return AutoScalingInstance.named(ownerFullName, name);
        }
    }
}