/*
* Copyright 2016 by PrimeCloud Controller/OSS Community.
*
* This file is part of PrimeCloud Controller(TM).
*
* PrimeCloud Controller(TM) 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, either version 2 of the License, or
* (at your option) any later version.
*
* PrimeCloud Controller(TM) 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 PrimeCloud Controller(TM). If not, see <http://www.gnu.org/licenses/>.
*/
package jp.primecloud.auto.service.impl;
import java.io.IOException;
import java.io.StringReader;
import java.security.GeneralSecurityException;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import javax.crypto.Cipher;
import jp.primecloud.auto.entity.crud.AwsAddress;
import jp.primecloud.auto.entity.crud.AwsInstance;
import jp.primecloud.auto.entity.crud.Farm;
import jp.primecloud.auto.entity.crud.Instance;
import jp.primecloud.auto.entity.crud.PlatformAws;
import jp.primecloud.auto.exception.AutoApplicationException;
import jp.primecloud.auto.process.aws.AwsProcessClient;
import jp.primecloud.auto.process.aws.AwsProcessClientFactory;
import jp.primecloud.auto.service.AwsDescribeService;
import jp.primecloud.auto.service.ServiceSupport;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.bouncycastle.openssl.PEMReader;
import com.amazonaws.services.ec2.model.AvailabilityZone;
import com.amazonaws.services.ec2.model.DescribeAvailabilityZonesRequest;
import com.amazonaws.services.ec2.model.DescribeAvailabilityZonesResult;
import com.amazonaws.services.ec2.model.DescribeKeyPairsRequest;
import com.amazonaws.services.ec2.model.DescribeKeyPairsResult;
import com.amazonaws.services.ec2.model.DescribeSecurityGroupsRequest;
import com.amazonaws.services.ec2.model.DescribeSecurityGroupsResult;
import com.amazonaws.services.ec2.model.DescribeSubnetsRequest;
import com.amazonaws.services.ec2.model.DescribeSubnetsResult;
import com.amazonaws.services.ec2.model.Filter;
import com.amazonaws.services.ec2.model.GetPasswordDataRequest;
import com.amazonaws.services.ec2.model.GetPasswordDataResult;
import com.amazonaws.services.ec2.model.KeyPairInfo;
import com.amazonaws.services.ec2.model.SecurityGroup;
import com.amazonaws.services.ec2.model.Subnet;
/**
* <p>
* TODO: クラスコメント
* </p>
*
*/
public class AwsDescribeServiceImpl extends ServiceSupport implements AwsDescribeService {
protected AwsProcessClientFactory awsProcessClientFactory;
/**
* {@inheritDoc}
*/
@Override
public List<AvailabilityZone> getAvailabilityZones(Long userNo, Long platformNo) {
// アベイラビリティゾーンを取得
AwsProcessClient awsProcessClient = awsProcessClientFactory.createAwsProcessClient(userNo, platformNo);
DescribeAvailabilityZonesRequest request = new DescribeAvailabilityZonesRequest();
DescribeAvailabilityZonesResult result = awsProcessClient.getEc2Client().describeAvailabilityZones(request);
List<AvailabilityZone> availabilityZones = result.getAvailabilityZones();
// ソート
Collections.sort(availabilityZones, Comparators.COMPARATOR_AVAILABILITY_ZONE);
return availabilityZones;
}
/**
* {@inheritDoc}
*/
@Override
public List<KeyPairInfo> getKeyPairs(Long userNo, Long platformNo) {
// キーペアを取得
AwsProcessClient awsProcessClient = awsProcessClientFactory.createAwsProcessClient(userNo, platformNo);
DescribeKeyPairsRequest request = new DescribeKeyPairsRequest();
DescribeKeyPairsResult result = awsProcessClient.getEc2Client().describeKeyPairs(request);
List<KeyPairInfo> keyPairs = result.getKeyPairs();
// ソート
Collections.sort(keyPairs, Comparators.COMPARATOR_KEY_PAIR_INFO);
return keyPairs;
}
/**
* {@inheritDoc}
*/
@Override
public List<SecurityGroup> getSecurityGroups(Long userNo, Long platformNo) {
// セキュリティグループを取得
AwsProcessClient awsProcessClient = awsProcessClientFactory.createAwsProcessClient(userNo, platformNo);
DescribeSecurityGroupsRequest request = new DescribeSecurityGroupsRequest();
PlatformAws platformAws = platformAwsDao.read(platformNo);
if (BooleanUtils.isTrue(platformAws.getVpc())) {
// VPCの場合、VPC IDが同じものを抽出
request.withFilters(new Filter().withName("vpc-id").withValues(platformAws.getVpcId()));
} else {
// 非VPCの場合、VPC IDが空のものを抽出
request.withFilters(new Filter().withName("vpc-id").withValues(""));
}
DescribeSecurityGroupsResult result = awsProcessClient.getEc2Client().describeSecurityGroups(request);
List<SecurityGroup> securityGroups = result.getSecurityGroups();
// ソート
Collections.sort(securityGroups, Comparators.COMPARATOR_SECURITY_GROUP);
return securityGroups;
}
/**
* {@inheritDoc}
*/
@Override
public List<Subnet> getSubnets(Long userNo, Long platformNo) {
// VPCかどうかのチェック
PlatformAws platformAws = platformAwsDao.read(platformNo);
if (BooleanUtils.isNotTrue(platformAws.getVpc())) {
// 非VPCの場合、サブネットはない
return new ArrayList<Subnet>();
}
// サブネットを取得
AwsProcessClient awsProcessClient = awsProcessClientFactory.createAwsProcessClient(userNo, platformNo);
DescribeSubnetsRequest request = new DescribeSubnetsRequest();
request.withFilters(new Filter().withName("vpc-id").withValues(platformAws.getVpcId()));
DescribeSubnetsResult result = awsProcessClient.getEc2Client().describeSubnets(request);
List<Subnet> subnets = result.getSubnets();
// プラットフォームにサブネットが指定されている場合、そのサブネットのみに制限する
if (StringUtils.isNotEmpty(awsProcessClient.getPlatformAws().getSubnetId())) {
List<String> subnetIds = new ArrayList<String>();
for (String subnetId : StringUtils.split(awsProcessClient.getPlatformAws().getSubnetId(), ",")) {
subnetIds.add(subnetId.trim());
}
List<Subnet> subnets2 = new ArrayList<Subnet>();
for (Subnet subnet : subnets) {
if (subnetIds.contains(subnet.getSubnetId())) {
subnets2.add(subnet);
}
}
subnets = subnets2;
}
// ソート
Collections.sort(subnets, Comparators.COMPARATOR_SUBNET);
return subnets;
}
/**
* {@inheritDoc}
*/
@Override
public List<AwsAddress> getAddresses(Long userNo, Long platformNo) {
// ユーザに紐づくAWSアドレス情報を取得
List<AwsAddress> allAwsAddresses = awsAddressDao.readByUserNo(userNo);
// プラットフォームが一致するものを抽出
List<AwsAddress> awsAddresses = new ArrayList<AwsAddress>();
for (AwsAddress awsAddress : allAwsAddresses) {
if (platformNo.equals(awsAddress.getPlatformNo())) {
awsAddresses.add(awsAddress);
}
}
// ソート
Collections.sort(awsAddresses, Comparators.COMPARATOR_AWS_ADDRESS);
return awsAddresses;
}
/**
* {@inheritDoc}
*/
@Override
public String getPassword(Long instanceNo, String privateKey) {
// PrivateKeyの取得
PrivateKey key = toPrivateKey(privateKey);
// パスワードデータの取得
String passwordData = getPasswordData(instanceNo);
// パスワードデータの復号
String password = decryptPasswordData(passwordData, key);
return password;
}
protected PrivateKey toPrivateKey(String privateKey) {
StringReader reader = new StringReader(privateKey);
// プライベートキーを読み込み
PEMReader pemReader = new PEMReader(reader);
try {
Object pemObject = pemReader.readObject();
KeyPair keyPair = KeyPair.class.cast(pemObject);
return keyPair.getPrivate();
} catch (Exception e) {
// プライベートキーの読み込みに失敗した場合
throw new AutoApplicationException("ESERVICE-000705", e);
} finally {
try {
pemReader.close();
} catch (IOException ignore) {
}
}
}
protected String getPasswordData(Long instanceNo) {
Instance instance = instanceDao.read(instanceNo);
Farm farm = farmDao.read(instance.getFarmNo());
AwsProcessClient awsProcessClient = awsProcessClientFactory.createAwsProcessClient(farm.getUserNo(),
instance.getPlatformNo());
AwsInstance awsInstance = awsInstanceDao.read(instanceNo);
// パスワードデータの取得
GetPasswordDataRequest request = new GetPasswordDataRequest();
request.withInstanceId(awsInstance.getInstanceId());
GetPasswordDataResult result = awsProcessClient.getEc2Client().getPasswordData(request);
return result.getPasswordData();
}
protected String decryptPasswordData(String passwordData, PrivateKey privateKey) {
// パスワードの復号
try {
Cipher cipher = Cipher.getInstance(privateKey.getAlgorithm());
cipher.init(Cipher.DECRYPT_MODE, privateKey);
byte[] binary = cipher.doFinal(Base64.decodeBase64(passwordData.getBytes()));
return new String(binary);
} catch (GeneralSecurityException e) {
// パスワードを復号できなかった場合
throw new AutoApplicationException("ESERVICE-000706", e);
}
}
public void setAwsProcessClientFactory(AwsProcessClientFactory awsProcessClientFactory) {
this.awsProcessClientFactory = awsProcessClientFactory;
}
}