package com.clouck.service;
import java.util.Collection;
import java.util.List;
import org.apache.commons.lang3.Validate;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.clouck.application.Ec2Filter;
import com.clouck.application.Ec2FilterName;
import com.clouck.converter.Ec2Converter;
import com.clouck.exception.ClouckUnexpectedConditionException;
import com.clouck.exception.CloudVersionIllegalStateException;
import com.clouck.model.Account;
import com.clouck.model.Region;
import com.clouck.model.ResourceType;
import com.clouck.model.aws.AbstractResource;
import com.clouck.model.aws.ec2.Ec2InstanceState;
import com.clouck.model.aws.ec2.Ec2SpotInstanceRequestState;
import com.clouck.model.aws.ec2.Ec2Version;
import com.clouck.util.ResourceUtil;
import com.clouck.validator.Ec2ResourceValidator;
import com.clouck.wrapper.aws.AsWrapper;
import com.clouck.wrapper.aws.Ec2Wrapper;
import com.clouck.wrapper.aws.ElbWrapper;
import com.clouck.wrapper.aws.IamWrapper;
import com.clouck.wrapper.rabbit.MQWrapper;
import com.google.common.base.Optional;
@Service
public class ResourceServiceImpl implements ResourceService {
private static final Logger log = LoggerFactory.getLogger(ResourceServiceImpl.class);
@Autowired
private Ec2Converter converter;
@Autowired
private AwsService awsService;
@Autowired
private BaseService baseService;
@Autowired
private Ec2ResourceValidator validator;
@Autowired
private Ec2Wrapper ec2;
@Autowired
private ElbWrapper elb;
@Autowired
private AsWrapper as;
@Autowired
private IamWrapper iam;
@Autowired
private MQWrapper mQWrapper;
@Autowired
private ResourceUtil resourceUtil;
@Override
public void scanAccount(Account account) {
log.debug("============scan account:({}==>{})============", account.getId(), account.getName());
for (ResourceType resourceType : ResourceType.findScaningResourceTypes()) {
if (resourceType.isMultiRegion()) {
for (Region region : Region.findAvailableRegions(resourceType)) {
mQWrapper.sendScanResourceMessage(account.getId(), resourceType, region);
}
} else {
mQWrapper.sendScanResourceMessage(account.getId(), resourceType);
}
}
}
@Override
public void convertEc2Reservation2Ec2Instance(Account account) {
Validate.notNull(account);
//TODO: Maybe have a locker here as well. just like others
String accountId = account.getId();
for (Region region : Region.findAvailableRegions(ResourceType.Ec2_Reservation)) {
Optional<Ec2Version> oLatestEc2Version = awsService.findLatestEc2Version(accountId, ResourceType.Ec2_Instance, region);
List<Ec2Version> ec2ReservationVersions = null;
if (oLatestEc2Version.isPresent()) {
DateTime dt = new DateTime(oLatestEc2Version.get().getTimeDetected());
ec2ReservationVersions = awsService.findEc2VersionsFromExcludeOrderByTimeDetected(accountId, ResourceType.Ec2_Reservation, region, dt);
} else {
ec2ReservationVersions = awsService.findEc2VersionsOrderByTimeDetectedAsc(accountId, ResourceType.Ec2_Reservation, region);
}
for (Ec2Version ec2ReservationVersion : ec2ReservationVersions) {
List<AbstractResource<?>> ec2Reservations = awsService.findResources(ec2ReservationVersion.getResourceIds(), ResourceType.Ec2_Reservation);
List<AbstractResource<?>> ec2Instances = converter.toEc2InstancesFromEc2Reservations(ec2Reservations, ec2ReservationVersion.getAccountId(), region, new DateTime(ec2ReservationVersion.getTimeDetected()));
boolean isNewEc2VersionAdded = addNewResources(account, region, ResourceType.Ec2_Instance, ec2Instances, new DateTime(ec2ReservationVersion.getTimeDetected()));
if (!isNewEc2VersionAdded) {
throw new ClouckUnexpectedConditionException(String.format("ec2 reservation version:%s " +
"should associate with one ec2 instance version, but got none added.", ec2ReservationVersion.getId()));
}
}
}
}
/**
*
* @param account
* @param region
* @param resourceType
* @param newResources
* @param dt the time we scan the resources
*/
@Override
public boolean addNewResources(Account account, Region region, ResourceType resourceType, List<AbstractResource<?>> newResources, DateTime dt) {
validator.isSameTime(newResources, dt);
validator.isLatestTime(account, region, resourceType, dt);
boolean isNewEc2VersionAdded = false;
// find existing resources
Optional<Ec2Version> oLatestVersion = awsService.findLatestEc2Version(account.getId(), resourceType, region);
if (!oLatestVersion.isPresent()) {
// maybe first time scan or a new region added
Ec2Version newEc2Version = new Ec2Version(account.getId(), region, dt.toDate(), resourceType);
saveResourcesAndEc2Version(newResources, newEc2Version);
isNewEc2VersionAdded = true;
} else {
List<AbstractResource<?>> existingResources = awsService.findResources(oLatestVersion.get().getResourceIds(), resourceType);
// compare resources
CompareResourceResult<AbstractResource<?>> result = resourceUtil.compareResources(existingResources, newResources);
// save them into db
if (result.getAddedResources().size() != 0 || result.getDeletedResourceIds().size() != 0) {
Ec2Version newEc2Version = new Ec2Version(account.getId(), region, dt.toDate(), resourceType);
for (String id : result.getUnchangedResourceIds()) {
newEc2Version.getResourceIds().add(id);
}
saveResourcesAndEc2Version(result.getAddedResources(), newEc2Version);
isNewEc2VersionAdded = true;
}
}
return isNewEc2VersionAdded;
}
private void saveResourcesAndEc2Version(Collection<? extends AbstractResource<?>> newResources, Ec2Version newEc2Version) {
baseService.insertAll(newResources);
for (AbstractResource<?> newResource : newResources) {
newEc2Version.getResourceIds().add(newResource.getId());
}
baseService.save(newEc2Version);
}
@Override
public List<AbstractResource<?>> findNewResources(Account account, Region region, ResourceType resourceType, DateTime dt) {
List<AbstractResource<?>> newResources = null;
switch (resourceType) {
case Ec2_Reservation:
Ec2Filter instanceFilter = new Ec2Filter().
withName(Ec2FilterName.INSTANCE_STATE_NAME).withValue(Ec2InstanceState.Pending.getState()).
withValue(Ec2InstanceState.Running.getState()).withValue(Ec2InstanceState.Shutting_Down.getState()).
withValue(Ec2InstanceState.Stopping.getState()).withValue(Ec2InstanceState.Stopped.getState());
newResources = ec2.describeReservations(account, region, dt, instanceFilter);
break;
case Ec2_Security_Group:
newResources = ec2.describeSecurityGroups(account, region, dt);
break;
case Ec2_Load_Balancer:
newResources = elb.describeLoadBalancers(account, region, dt);
break;
case Ec2_Ami:
Ec2Filter imageFilter = new Ec2Filter().withName(Ec2FilterName.OWNER_ID).withValue(account.getAccountNumber());
newResources = ec2.describeAMIs(account, region, dt, imageFilter);
break;
case Ec2_Volume:
newResources = ec2.describeVolumes(account, region, dt);
break;
case Ec2_Snapshot:
Ec2Filter snapshotFilter = new Ec2Filter().withName(Ec2FilterName.OWNER_ID).withValue(account.getAccountNumber());
newResources = ec2.describeSnapshots(account, region, dt, snapshotFilter);
break;
case Ec2_Key_Pair:
newResources = ec2.describeKeyPairs(account, region, dt);
break;
case Ec2_Launch_Configuration:
newResources = as.describeLaunchConfigurations(account, region, dt);
break;
case Ec2_Auto_Scaling_Group:
newResources = as.describeAutoScalingGroups(account, region, dt);
break;
case Ec2_Elastic_IP:
newResources = ec2.describeElasticIPs(account, region, dt);
break;
case Ec2_Placement_Group:
newResources = ec2.describePlacementGroups(account, region, dt);
break;
case Ec2_Network_Interface:
newResources = ec2.describeNetworkInterfaces(account, region, dt);
break;
case Ec2_Spot_Instance_Request:
Ec2Filter spotInstanceRequestFilter = new Ec2Filter().
withName(Ec2FilterName.STATE).withValue(Ec2SpotInstanceRequestState.Open.getState()).
withValue(Ec2SpotInstanceRequestState.Active.getState()).withValue(Ec2SpotInstanceRequestState.Closed.getState()).
withValue(Ec2SpotInstanceRequestState.Failed.getState());
newResources = ec2.describeSpotInstanceRequests(account, region, dt, spotInstanceRequestFilter);
break;
case Iam_Group:
newResources = iam.listGroups(account, dt);
break;
case Iam_User:
newResources = iam.listUsers(account, dt);
break;
case Iam_Role:
newResources = iam.listRoles(account, dt);
break;
case Vpc_Vpc:
newResources = ec2.describeVpcs(account, region, dt);
break;
case Vpc_Subnet:
newResources = ec2.describeSubnets(account, region, dt);
break;
case Vpc_Route_Table:
newResources = ec2.describeRouteTables(account, region, dt);
break;
case Vpc_Internet_Gateway:
newResources = ec2.describeInternetGateways(account, region, dt);
break;
case Vpc_DhcpOptions:
newResources = ec2.describeDhcpOptions(account, region, dt);
break;
case Vpc_NetworkAcl:
newResources = ec2.describeNetworkAcls(account, region, dt);
break;
default:
throw new CloudVersionIllegalStateException("invalid resource type:" + resourceType);
}
return newResources;
}
}