org.jclouds.aliyun.ecs.compute.ECSComputeServiceAdapter.java Source code

Java tutorial

Introduction

Here is the source code for org.jclouds.aliyun.ecs.compute.ECSComputeServiceAdapter.java

Source

/*
 * Licensed to the Apache Software Foundation (ASF) under one or more
 * contributor license agreements.  See the NOTICE file distributed with
 * this work for additional information regarding copyright ownership.
 * The ASF licenses this file to You 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 org.jclouds.aliyun.ecs.compute;

import com.google.common.base.Function;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import com.google.common.base.Supplier;
import com.google.common.collect.FluentIterable;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Iterables;
import com.google.common.collect.Lists;
import org.jclouds.aliyun.ecs.ECSComputeServiceApi;
import org.jclouds.aliyun.ecs.compute.strategy.CleanupResources;
import org.jclouds.aliyun.ecs.domain.AvailableResource;
import org.jclouds.aliyun.ecs.domain.AvailableZone;
import org.jclouds.aliyun.ecs.domain.Image;
import org.jclouds.aliyun.ecs.domain.Instance;
import org.jclouds.aliyun.ecs.domain.InstanceRequest;
import org.jclouds.aliyun.ecs.domain.InstanceType;
import org.jclouds.aliyun.ecs.domain.Region;
import org.jclouds.aliyun.ecs.domain.SupportedResource;
import org.jclouds.aliyun.ecs.domain.options.CreateInstanceOptions;
import org.jclouds.aliyun.ecs.domain.options.ListImagesOptions;
import org.jclouds.aliyun.ecs.domain.options.ListInstancesOptions;
import org.jclouds.aliyun.ecs.domain.options.TagOptions;
import org.jclouds.aliyun.ecs.domain.regionscoped.ImageInRegion;
import org.jclouds.aliyun.ecs.domain.regionscoped.RegionAndId;
import org.jclouds.aliyun.ecs.compute.options.ECSServiceTemplateOptions;
import org.jclouds.compute.ComputeServiceAdapter;
import org.jclouds.compute.domain.Template;
import org.jclouds.compute.reference.ComputeServiceConstants;
import org.jclouds.compute.util.ComputeServiceUtils;
import org.jclouds.logging.Logger;

import javax.annotation.Nullable;
import javax.annotation.Resource;
import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import java.util.List;
import java.util.Map;
import java.util.Set;

import static com.google.common.base.Preconditions.checkState;
import static com.google.common.collect.Iterables.contains;
import static com.google.common.collect.Lists.newArrayList;
import static java.lang.String.format;
import static org.jclouds.aliyun.ecs.domain.regionscoped.RegionAndId.fromSlashEncoded;
import static org.jclouds.aliyun.ecs.domain.regionscoped.RegionAndId.slashEncodeRegionAndId;
import static org.jclouds.compute.config.ComputeServiceProperties.TIMEOUT_NODE_SUSPENDED;

/**
 * defines the connection between the {@link ECSComputeServiceApi} implementation and
 * the jclouds {@link org.jclouds.compute.ComputeService}
 */
@Singleton
public class ECSComputeServiceAdapter
        implements ComputeServiceAdapter<Instance, InstanceType, ImageInRegion, Region> {

    private final ECSComputeServiceApi api;
    private final Predicate<String> instanceSuspendedPredicate;

    private final Supplier<Set<String>> regionIds;
    private final CleanupResources cleanupResources;

    @Resource
    @Named(ComputeServiceConstants.COMPUTE_LOGGER)
    protected Logger logger = Logger.NULL;

    @Inject
    ECSComputeServiceAdapter(ECSComputeServiceApi api,
            @Named(TIMEOUT_NODE_SUSPENDED) Predicate<String> instanceSuspendedPredicate,
            @org.jclouds.location.Region Supplier<Set<String>> regionIds, CleanupResources cleanupResources) {
        this.api = api;
        this.instanceSuspendedPredicate = instanceSuspendedPredicate;
        this.regionIds = regionIds;
        this.cleanupResources = cleanupResources;
    }

    @Override
    public NodeAndInitialCredentials<Instance> createNodeWithGroupEncodedIntoName(String group, String name,
            Template template) {
        String instanceType = template.getHardware().getId();
        String regionId = template.getLocation().getId();
        String imageId = template.getImage().getId();

        ECSServiceTemplateOptions templateOptions = template.getOptions().as(ECSServiceTemplateOptions.class);

        String keyPairName = templateOptions.getKeyPairName();
        String securityGroupId = Iterables.getOnlyElement(templateOptions.getGroups());
        String vSwitchId = templateOptions.getVSwitchId();
        Instance.InternetChargeType internetChargeType = Instance.InternetChargeType
                .fromValue(templateOptions.getInternetChargeType());
        int internetMaxBandwidthOut = templateOptions.getInternetMaxBandwidthOut();
        String instanceChargeType = templateOptions.getInstanceChargeType();

        Map<String, String> tags = ComputeServiceUtils.metadataAndTagsAsValuesOfEmptyString(templateOptions);
        tags = new ImmutableMap.Builder().putAll(tags).put(vSwitchId, "").build();
        TagOptions tagOptions = TagOptions.Builder.tags(tags);

        InstanceRequest instanceRequest = api.instanceApi().create(regionId,
                RegionAndId.fromSlashEncoded(imageId).id(), securityGroupId, name, instanceType,
                CreateInstanceOptions.Builder.vSwitchId(vSwitchId).internetChargeType(internetChargeType.toString())
                        .internetMaxBandwidthOut(internetMaxBandwidthOut).instanceChargeType(instanceChargeType)
                        .instanceName(name).keyPairName(keyPairName).tagOptions(tagOptions));

        String regionAndInstanceId = slashEncodeRegionAndId(regionId, instanceRequest.getInstanceId());
        if (!instanceSuspendedPredicate.apply(regionAndInstanceId)) {
            final String message = format(
                    "Instance %s was not created correctly. The associated resources created for it will be destroyed",
                    instanceRequest.getInstanceId());
            logger.warn(message);
            cleanupResources.cleanupNode(RegionAndId.create(regionId, instanceRequest.getInstanceId()));
            cleanupResources.cleanupSecurityGroupIfOrphaned(regionId, securityGroupId);
        }

        api.instanceApi().allocatePublicIpAddress(regionId, instanceRequest.getInstanceId());
        api.instanceApi().powerOn(instanceRequest.getInstanceId());
        Instance instance = Iterables.get(api.instanceApi().list(regionId,
                ListInstancesOptions.Builder.instanceIds(instanceRequest.getInstanceId())), 0);

        // Safe to pass null credentials here, as jclouds will default populate
        // the node with the default credentials from the image, or the ones in
        // the options, if provided.
        return new NodeAndInitialCredentials(instance,
                slashEncodeRegionAndId(regionId, instanceRequest.getInstanceId()), null);
    }

    @Override
    public Iterable<InstanceType> listHardwareProfiles() {
        final ImmutableSet.Builder<String> instanceTypeIdsBuilder = ImmutableSet.builder();
        for (String regionId : getAvailableLocationNames()) {
            instanceTypeIdsBuilder.addAll(getInstanceTypeIds(regionId));
        }
        final Set<String> ids = instanceTypeIdsBuilder.build();

        List<InstanceType> instanceTypes = FluentIterable.from(api.instanceApi().listTypes())
                .filter(new Predicate<InstanceType>() {
                    @Override
                    public boolean apply(@Nullable InstanceType input) {
                        return contains(ids, input.id());
                    }
                }).toList();

        return instanceTypes;
    }

    private List<String> getInstanceTypeIds(String regionId) {
        List<String> instanceTypeIds = Lists.newArrayList();
        for (AvailableZone availableZone : api.instanceApi().listInstanceTypesByAvailableZone(regionId)) {
            for (AvailableResource availableResource : availableZone.availableResources()
                    .get("AvailableResource")) {
                for (SupportedResource supportedResource : availableResource.supportedResources()
                        .get("SupportedResource")) {
                    if (SupportedResource.Status.AVAILABLE == supportedResource.status()) {
                        instanceTypeIds.add(supportedResource.value());
                    }
                }
            }
        }
        return instanceTypeIds;
    }

    @Override
    public Iterable<ImageInRegion> listImages() {
        final ImmutableList.Builder<ImageInRegion> imagesInRegion = ImmutableList.builder();

        for (final String regionId : getAvailableLocationNames()) {
            imagesInRegion
                    .addAll(api.imageApi().list(regionId).concat().transform(new Function<Image, ImageInRegion>() {
                        @Override
                        public ImageInRegion apply(Image image) {
                            return ImageInRegion.create(regionId, image);
                        }
                    }));
        }
        return imagesInRegion.build();
    }

    @Override
    public ImageInRegion getImage(final String id) {
        RegionAndId regionAndId = fromSlashEncoded(id);
        Image image = api.imageApi()
                .list(regionAndId.regionId(), ListImagesOptions.Builder.imageIds(regionAndId.id()))
                .firstMatch(Predicates.<Image>notNull()).orNull();
        if (image == null)
            return null;
        return ImageInRegion.create(regionAndId.regionId(), image);
    }

    @Override
    public Iterable<Region> listLocations() {
        return FluentIterable.from(api.regionAndZoneApi().describeRegions()).filter(new Predicate<Region>() {
            @Override
            public boolean apply(Region region) {
                return regionIds.get().isEmpty() ? true : regionIds.get().contains(region.id());
            }
        }).toList();
    }

    @Override
    public Instance getNode(final String id) {
        RegionAndId regionAndId = fromSlashEncoded(id);
        return api.instanceApi()
                .list(regionAndId.regionId(), ListInstancesOptions.Builder.instanceIds(regionAndId.id()))
                .firstMatch(Predicates.<Instance>notNull()).orNull();
    }

    @Override
    public void destroyNode(String id) {
        checkState(cleanupResources.cleanupNode(RegionAndId.fromSlashEncoded(id)),
                "server(%s) and its resources still there after deleting!?", id);
    }

    @Override
    public void rebootNode(String id) {
        api.instanceApi().reboot(id);
    }

    @Override
    public void resumeNode(String id) {
        api.instanceApi().powerOn(id);
    }

    @Override
    public void suspendNode(String id) {
        api.instanceApi().powerOff(id);
    }

    @Override
    public Iterable<Instance> listNodes() {
        final ImmutableList.Builder<Instance> instances = ImmutableList.builder();
        for (String regionId : getAvailableLocationNames()) {
            instances.addAll(api.instanceApi().list(regionId).concat());
        }
        return instances.build();
    }

    @Override
    public Iterable<Instance> listNodesByIds(final Iterable<String> ids) {

        final ImmutableList.Builder<Instance> instancesBuilder = ImmutableList.builder();
        for (String regionId : getAvailableLocationNames()) {
            instancesBuilder.addAll(api.instanceApi().list(regionId,
                    ListInstancesOptions.Builder.instanceIds(Iterables.toArray(ids, String.class))));
        }
        return instancesBuilder.build();
    }

    private List<String> getAvailableLocationNames() {
        return newArrayList(Iterables.transform(listLocations(), new Function<Region, String>() {
            @Override
            public String apply(Region location) {
                return location.id();
            }
        }));
    }

}