/*
* 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.process.aws;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;
import jp.primecloud.auto.config.Config;
import jp.primecloud.auto.entity.crud.AwsInstance;
import jp.primecloud.auto.entity.crud.Farm;
import jp.primecloud.auto.entity.crud.Image;
import jp.primecloud.auto.entity.crud.ImageAws;
import jp.primecloud.auto.entity.crud.Instance;
import jp.primecloud.auto.entity.crud.Platform;
import jp.primecloud.auto.entity.crud.PlatformAws;
import jp.primecloud.auto.entity.crud.User;
import jp.primecloud.auto.exception.AutoException;
import jp.primecloud.auto.process.ProcessLogger;
import jp.primecloud.auto.service.ServiceSupport;
import jp.primecloud.auto.util.MessageUtils;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.lang.BooleanUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import com.amazonaws.services.ec2.model.BlockDeviceMapping;
import com.amazonaws.services.ec2.model.DeviceType;
import com.amazonaws.services.ec2.model.GetPasswordDataRequest;
import com.amazonaws.services.ec2.model.GetPasswordDataResult;
import com.amazonaws.services.ec2.model.GroupIdentifier;
import com.amazonaws.services.ec2.model.InstanceBlockDeviceMapping;
import com.amazonaws.services.ec2.model.InstanceStateChange;
import com.amazonaws.services.ec2.model.InstanceStateName;
import com.amazonaws.services.ec2.model.ModifyInstanceAttributeRequest;
import com.amazonaws.services.ec2.model.Placement;
import com.amazonaws.services.ec2.model.PlatformValues;
import com.amazonaws.services.ec2.model.Reservation;
import com.amazonaws.services.ec2.model.RunInstancesRequest;
import com.amazonaws.services.ec2.model.RunInstancesResult;
import com.amazonaws.services.ec2.model.SecurityGroup;
import com.amazonaws.services.ec2.model.StartInstancesRequest;
import com.amazonaws.services.ec2.model.StartInstancesResult;
import com.amazonaws.services.ec2.model.StopInstancesRequest;
import com.amazonaws.services.ec2.model.StopInstancesResult;
import com.amazonaws.services.ec2.model.Tag;
import com.amazonaws.services.ec2.model.TerminateInstancesRequest;
import com.amazonaws.services.ec2.model.TerminateInstancesResult;
/**
* <p>
* TODO: クラスコメントを記述
* </p>
*
*/
public class AwsInstanceProcess extends ServiceSupport {
protected AwsCommonProcess awsCommonProcess;
protected ProcessLogger processLogger;
/**
* TODO: メソッドコメント
*
* @param awsProcessClient
* @param instanceNo
*/
public void startInstance(AwsProcessClient awsProcessClient, Long instanceNo) {
AwsInstance awsInstance = awsInstanceDao.read(instanceNo);
Instance instance = instanceDao.read(instanceNo);
Image image = imageDao.read(instance.getImageNo());
ImageAws imageAws = imageAwsDao.read(instance.getImageNo());
// インスタンスストアイメージの場合や、EBSイメージで初回起動の場合
if (BooleanUtils.isNotTrue(imageAws.getEbsImage()) || StringUtils.isEmpty(awsInstance.getInstanceId())) {
// インスタンスIDがある場合はスキップ
if (!StringUtils.isEmpty(awsInstance.getInstanceId())) {
return;
}
// インスタンスの作成
run(awsProcessClient, instanceNo);
// インスタンスの作成待ち
waitRun(awsProcessClient, instanceNo);
// インスタンスにタグをつける
createTag(awsProcessClient, instanceNo);
// Windowsの場合、パスワードデータを取得できるようになるまで待つ
if (StringUtils.startsWithIgnoreCase(image.getOs(), "windows")) {
waitGetPasswordData(awsProcessClient, instanceNo);
}
}
// EBSイメージで2回目以降の起動の場合
else {
// インスタンスが停止中でない場合はスキップ
if (!StringUtils.equals(awsInstance.getStatus(), InstanceStateName.Stopped.toString())) {
return;
}
// インスタンスの設定変更
modify(awsProcessClient, instanceNo);
// インスタンスの起動
start(awsProcessClient, instanceNo);
// インスタンスの起動待ち
waitStart(awsProcessClient, instanceNo);
}
}
/**
* TODO: メソッドコメント
*
* @param awsProcessClient
* @param instanceNo
*/
public void stopInstance(AwsProcessClient awsProcessClient, Long instanceNo) {
AwsInstance awsInstance = awsInstanceDao.read(instanceNo);
// インスタンスIDがない場合はスキップ
if (StringUtils.isEmpty(awsInstance.getInstanceId())) {
return;
}
Instance instance = instanceDao.read(instanceNo);
ImageAws imageAws = imageAwsDao.read(instance.getImageNo());
// インスタンスストアイメージの場合
if (BooleanUtils.isNotTrue(imageAws.getEbsImage())) {
try {
// インスタンスの削除
terminate(awsProcessClient, instanceNo);
// インスタンスの削除待ち
waitTerminate(awsProcessClient, instanceNo);
} catch (AutoException ignore) {
// 情報が不整合(インスタンス異常終了時など)の場合、警告ログと後始末のみ行う
log.warn(ignore.getMessage());
awsInstance = awsInstanceDao.read(instanceNo);
awsInstance.setInstanceId(null);
awsInstance.setStatus(null);
awsInstance.setDnsName(null);
awsInstance.setPrivateDnsName(null);
awsInstance.setIpAddress(null);
awsInstance.setPrivateIpAddress(null);
awsInstanceDao.update(awsInstance);
}
}
// EBSイメージの場合
else {
// インスタンスの停止
stop(awsProcessClient, instanceNo);
// インスタンスの停止待ち
waitStop(awsProcessClient, instanceNo);
}
}
public void run(AwsProcessClient awsProcessClient, Long instanceNo) {
Instance instance = instanceDao.read(instanceNo);
AwsInstance awsInstance = awsInstanceDao.read(instanceNo);
ImageAws imageAws = imageAwsDao.read(instance.getImageNo());
PlatformAws platformAws = awsProcessClient.getPlatformAws();
// インスタンス作成情報
RunInstancesRequest request = new RunInstancesRequest();
request.withMinCount(1);
request.withMaxCount(1);
request.withImageId(imageAws.getImageId());
request.withKernelId(StringUtils.isEmpty(imageAws.getKernelId()) ? null : imageAws.getKernelId());
request.withRamdiskId(StringUtils.isEmpty(imageAws.getRamdiskId()) ? null : imageAws.getRamdiskId());
request.withKeyName(awsInstance.getKeyName());
request.withInstanceType(awsInstance.getInstanceType());
// UserData
Map<String, String> userData = createUserData(instanceNo);
request.withUserData(encodeUserData(userData));
// 非VPCの場合
if (BooleanUtils.isNotTrue(platformAws.getVpc())) {
// AvailabilityZone
if (StringUtils.isNotEmpty(awsInstance.getAvailabilityZone())) {
request.withPlacement(new Placement(awsInstance.getAvailabilityZone()));
}
// SecurityGroup
if (StringUtils.isNotEmpty(awsInstance.getSecurityGroups())) {
for (String groupName : StringUtils.split(awsInstance.getSecurityGroups(), ",")) {
request.withSecurityGroups(groupName.trim());
}
}
}
// VPCの場合
else {
// Subnet
request.withSubnetId(awsInstance.getSubnetId());
// SecurytiGroup
List<SecurityGroup> securityGroups = awsCommonProcess.describeSecurityGroupsByVpcId(awsProcessClient,
platformAws.getVpcId());
for (String groupName : StringUtils.split(awsInstance.getSecurityGroups(), ",")) {
groupName = groupName.trim();
for (SecurityGroup securityGroup : securityGroups) {
if (StringUtils.equals(groupName, securityGroup.getGroupName())) {
request.withSecurityGroupIds(securityGroup.getGroupId());
break;
}
}
}
// PrivateIpAddress
if (StringUtils.isNotEmpty(awsInstance.getPrivateIpAddress())) {
request.withPrivateIpAddress(awsInstance.getPrivateIpAddress());
}
}
// BlockDeviceMapping
List<BlockDeviceMapping> blockDeviceMappings = createBlockDeviceMappings(awsProcessClient, imageAws,
awsInstance);
request.withBlockDeviceMappings(blockDeviceMappings);
// イベントログ出力
processLogger.debug(null, instance, "AwsInstanceCreate", new Object[] { awsProcessClient.getPlatform()
.getPlatformName() });
// インスタンスの作成
RunInstancesResult result = awsProcessClient.getEc2Client().runInstances(request);
Reservation reservation = result.getReservation();
if (reservation == null || reservation.getInstances().size() != 1) {
// インスタンス作成失敗時
throw new AutoException("EPROCESS-000105");
}
com.amazonaws.services.ec2.model.Instance instance2 = reservation.getInstances().get(0);
// ログ出力
if (log.isInfoEnabled()) {
log.info(MessageUtils.getMessage("IPROCESS-100115", instance2.getInstanceId()));
}
// データベース更新
awsInstance.setInstanceId(instance2.getInstanceId());
awsInstance.setStatus(instance2.getState().getName());
awsInstanceDao.update(awsInstance);
}
public void waitRun(AwsProcessClient awsProcessClient, Long instanceNo) {
AwsInstance awsInstance = awsInstanceDao.read(instanceNo);
String instanceId = awsInstance.getInstanceId();
// インスタンスの作成待ち
com.amazonaws.services.ec2.model.Instance instance = awsCommonProcess
.waitInstance(awsProcessClient, instanceId);
if (!instance.getState().getName().equals(InstanceStateName.Running.toString())) {
// インスタンス作成失敗時
AutoException exception = new AutoException("EPROCESS-000106", instanceId, instance.getState().getName());
exception.addDetailInfo("result=" + ReflectionToStringBuilder.toString(instance));
throw exception;
}
// ログ出力
if (log.isInfoEnabled()) {
log.info(MessageUtils.getMessage("IPROCESS-100116", instanceId));
}
// イベントログ出力
Instance instance2 = instanceDao.read(instanceNo);
processLogger.debug(null, instance2, "AwsInstanceCreateFinish", new Object[] {
awsProcessClient.getPlatform().getPlatformName(), instanceId });
// データベース更新
awsInstance.setAvailabilityZone(instance.getPlacement().getAvailabilityZone());
awsInstance.setStatus(instance.getState().getName());
awsInstance.setDnsName(instance.getPublicDnsName());
awsInstance.setPrivateDnsName(instance.getPrivateDnsName());
awsInstance.setIpAddress(instance.getPublicIpAddress());
awsInstance.setPrivateIpAddress(instance.getPrivateIpAddress());
awsInstanceDao.update(awsInstance);
}
public void modify(AwsProcessClient awsProcessClient, Long instanceNo) {
AwsInstance awsInstance = awsInstanceDao.read(instanceNo);
String instanceId = awsInstance.getInstanceId();
com.amazonaws.services.ec2.model.Instance instance2 = awsCommonProcess.describeInstance(awsProcessClient,
instanceId);
// InstanceType
if (!StringUtils.equals(awsInstance.getInstanceType(), instance2.getInstanceType())) {
// InstanceTypeを変更する
ModifyInstanceAttributeRequest request = new ModifyInstanceAttributeRequest();
request.withInstanceId(instanceId);
request.withInstanceType(awsInstance.getInstanceType());
awsProcessClient.getEc2Client().modifyInstanceAttribute(request);
// ログ出力
if (log.isInfoEnabled()) {
log.info(MessageUtils.getMessage("IPROCESS-100161", instanceId));
}
}
// SecurityGroup
if (BooleanUtils.isTrue(awsProcessClient.getPlatformAws().getVpc())) {
// 現在設定されているSecurityGroup
List<String> groupNames = new ArrayList<String>();
List<GroupIdentifier> groupIdentifiers = instance2.getSecurityGroups();
for (GroupIdentifier groupIdentifier : groupIdentifiers) {
groupNames.add(groupIdentifier.getGroupName());
}
// 新しく設定するSecurityGroup
List<String> newGroupNames = new ArrayList<String>();
for (String groupName : StringUtils.split(awsInstance.getSecurityGroups(), ",")) {
newGroupNames.add(groupName.trim());
}
// SecurityGroupに変更があるかどうか
if (!(groupNames.size() == newGroupNames.size()) || !groupNames.containsAll(newGroupNames)) {
// SecurityGroupのIDを取得する
List<String> newSecurityGroups = new ArrayList<String>();
List<SecurityGroup> securityGroups = awsCommonProcess.describeSecurityGroupsByVpcId(awsProcessClient,
awsProcessClient.getPlatformAws().getVpcId());
for (String groupName : newGroupNames) {
for (SecurityGroup securityGroup : securityGroups) {
if (StringUtils.equals(groupName, securityGroup.getGroupName())) {
newSecurityGroups.add(securityGroup.getGroupId());
break;
}
}
}
// SecurityGroupを変更する
ModifyInstanceAttributeRequest request = new ModifyInstanceAttributeRequest();
request.withInstanceId(instanceId);
request.withGroups(newSecurityGroups);
awsProcessClient.getEc2Client().modifyInstanceAttribute(request);
// ログ出力
if (log.isInfoEnabled()) {
log.info(MessageUtils.getMessage("IPROCESS-100162", instanceId));
}
}
}
}
public void start(AwsProcessClient awsProcessClient, Long instanceNo) {
AwsInstance awsInstance = awsInstanceDao.read(instanceNo);
String instanceId = awsInstance.getInstanceId();
// イベントログ出力
Instance instance = instanceDao.read(instanceNo);
processLogger.debug(null, instance, "AwsInstanceStart", new Object[] {
awsProcessClient.getPlatform().getPlatformName(), instanceId });
// インスタンスの起動
StartInstancesRequest request = new StartInstancesRequest();
request.withInstanceIds(instanceId);
StartInstancesResult result = awsProcessClient.getEc2Client().startInstances(request);
List<InstanceStateChange> startingInstances = result.getStartingInstances();
// API実行結果チェック
if (startingInstances.size() == 0) {
// インスタンス起動失敗時
throw new AutoException("EPROCESS-000125", instanceId);
} else if (startingInstances.size() > 1) {
// 複数のインスタンスが起動した場合
AutoException exception = new AutoException("EPROCESS-000127", instanceId);
exception.addDetailInfo("result=" + startingInstances);
throw exception;
}
// ログ出力
if (log.isInfoEnabled()) {
log.info(MessageUtils.getMessage("IPROCESS-100111", instanceId));
}
// データベース更新
awsInstance.setStatus(startingInstances.get(0).getCurrentState().getName());
awsInstanceDao.update(awsInstance);
}
public void waitStart(AwsProcessClient awsProcessClient, Long instanceNo) {
AwsInstance awsInstance = awsInstanceDao.read(instanceNo);
String instanceId = awsInstance.getInstanceId();
// インスタンスの起動待ち
com.amazonaws.services.ec2.model.Instance instance = awsCommonProcess
.waitInstance(awsProcessClient, instanceId);
if (!instance.getState().getName().equals(InstanceStateName.Running.toString())) {
// インスタンス起動失敗時
AutoException exception = new AutoException("EPROCESS-000126", instanceId, instance.getState().getName());
exception.addDetailInfo("result=" + ReflectionToStringBuilder.toString(instance));
throw exception;
}
// ログ出力
if (log.isInfoEnabled()) {
log.info(MessageUtils.getMessage("IPROCESS-100112", instanceId));
}
// イベントログ出力
Instance instance2 = instanceDao.read(instanceNo);
processLogger.debug(null, instance2, "AwsInstanceStartFinish", new Object[] {
awsProcessClient.getPlatform().getPlatformName(), instanceId });
// データベース更新
awsInstance.setAvailabilityZone(instance.getPlacement().getAvailabilityZone());
awsInstance.setStatus(instance.getState().getName());
awsInstance.setDnsName(instance.getPublicDnsName());
awsInstance.setPrivateDnsName(instance.getPrivateDnsName());
awsInstance.setIpAddress(instance.getPublicIpAddress());
awsInstance.setPrivateIpAddress(instance.getPrivateIpAddress());
awsInstanceDao.update(awsInstance);
}
public void stop(AwsProcessClient awsProcessClient, Long instanceNo) {
AwsInstance awsInstance = awsInstanceDao.read(instanceNo);
String instanceId = awsInstance.getInstanceId();
// イベントログ出力
Instance instance = instanceDao.read(instanceNo);
processLogger.debug(null, instance, "AwsInstanceStop", new Object[] {
awsProcessClient.getPlatform().getPlatformName(), instanceId });
// インスタンスの停止
StopInstancesRequest request = new StopInstancesRequest();
request.withInstanceIds(instanceId);
StopInstancesResult result = awsProcessClient.getEc2Client().stopInstances(request);
List<InstanceStateChange> stoppingInstances = result.getStoppingInstances();
// API実行結果チェック
if (stoppingInstances.size() == 0) {
// インスタンス停止失敗時
throw new AutoException("EPROCESS-000128", instanceId);
} else if (stoppingInstances.size() > 1) {
// 複数のインスタンスが停止した場合
AutoException exception = new AutoException("EPROCESS-000130", instanceId);
exception.addDetailInfo("result=" + stoppingInstances);
throw exception;
}
// ログ出力
if (log.isInfoEnabled()) {
log.info(MessageUtils.getMessage("IPROCESS-100113", instanceId));
}
// データベース更新
awsInstance.setStatus(stoppingInstances.get(0).getCurrentState().getName());
awsInstanceDao.update(awsInstance);
}
public void waitStop(AwsProcessClient awsProcessClient, Long instanceNo) {
AwsInstance awsInstance = awsInstanceDao.read(instanceNo);
String instanceId = awsInstance.getInstanceId();
// インスタンスの停止待ち
com.amazonaws.services.ec2.model.Instance instance = awsCommonProcess
.waitInstance(awsProcessClient, instanceId);
if (!instance.getState().getName().equals(InstanceStateName.Stopped.toString())) {
// インスタンス停止失敗時
AutoException exception = new AutoException("EPROCESS-000129", instanceId, instance.getState().getName());
exception.addDetailInfo("result=" + ReflectionToStringBuilder.toString(instance));
throw exception;
}
// ログ出力
if (log.isInfoEnabled()) {
log.info(MessageUtils.getMessage("IPROCESS-100114", instanceId));
}
// イベントログ出力
Instance instance2 = instanceDao.read(instanceNo);
processLogger.debug(null, instance2, "AwsInstanceStopFinish", new Object[] {
awsProcessClient.getPlatform().getPlatformName(), instanceId });
// データベース更新
awsInstance.setAvailabilityZone(instance.getPlacement().getAvailabilityZone());
awsInstance.setStatus(instance.getState().getName());
awsInstance.setDnsName(instance.getPublicDnsName());
awsInstance.setPrivateDnsName(instance.getPrivateDnsName());
awsInstance.setIpAddress(instance.getPublicIpAddress());
awsInstance.setPrivateIpAddress(instance.getPrivateIpAddress());
awsInstanceDao.update(awsInstance);
}
public void terminate(AwsProcessClient awsProcessClient, Long instanceNo) {
AwsInstance awsInstance = awsInstanceDao.read(instanceNo);
String instanceId = awsInstance.getInstanceId();
// イベントログ出力
Instance instance = instanceDao.read(instanceNo);
processLogger.debug(null, instance, "AwsInstanceDelete", new Object[] {
awsProcessClient.getPlatform().getPlatformName(), instanceId });
// インスタンスの削除
TerminateInstancesRequest request = new TerminateInstancesRequest();
request.withInstanceIds(instanceId);
TerminateInstancesResult result = awsProcessClient.getEc2Client().terminateInstances(request);
List<InstanceStateChange> terminatingInstances = result.getTerminatingInstances();
// API実行結果チェック
if (terminatingInstances.size() == 0) {
// インスタンス削除失敗時
throw new AutoException("EPROCESS-000107", instanceId);
} else if (terminatingInstances.size() > 1) {
// 複数のインスタンスが削除された場合
AutoException exception = new AutoException("EPROCESS-000108", instanceId);
exception.addDetailInfo("result=" + terminatingInstances);
throw exception;
}
// ログ出力
if (log.isInfoEnabled()) {
log.info(MessageUtils.getMessage("IPROCESS-100117", instanceId));
}
// データベース更新
awsInstance.setStatus(terminatingInstances.get(0).getCurrentState().getName());
awsInstanceDao.update(awsInstance);
}
public void waitTerminate(AwsProcessClient awsProcessClient, Long instanceNo) {
AwsInstance awsInstance = awsInstanceDao.read(instanceNo);
String instanceId = awsInstance.getInstanceId();
// インスタンスの削除待ち
com.amazonaws.services.ec2.model.Instance instance;
try {
instance = awsCommonProcess.waitInstance(awsProcessClient, instanceId);
if (!StringUtils.equals(instance.getState().getName(), InstanceStateName.Terminated.toString())) {
// インスタンス削除失敗時
AutoException exception = new AutoException("EPROCESS-000109", instanceId, instance.getState()
.getName());
exception.addDetailInfo("result=" + ReflectionToStringBuilder.toString(instance));
throw exception;
}
} catch (AutoException e) {
// インスタンス情報を参照できない場合、既に削除されたものとして例外を無視する
if ("EPROCESS-000101".equals(e.getCode())) {
instance = null;
} else {
throw e;
}
}
// ログ出力
if (log.isInfoEnabled()) {
log.info(MessageUtils.getMessage("IPROCESS-100118", instanceId));
}
// イベントログ出力
Instance instance2 = instanceDao.read(instanceNo);
processLogger.debug(null, instance2, "AwsInstanceDeleteFinish", new Object[] {
awsProcessClient.getPlatform().getPlatformName(), instanceId });
String status = null;
if (instance != null) {
status = instance.getState().getName();
}
// データベース更新
awsInstance.setInstanceId(null);
awsInstance.setStatus(status);
awsInstance.setDnsName(null);
awsInstance.setPrivateDnsName(null);
awsInstance.setIpAddress(null);
awsInstance.setPrivateIpAddress(null);
awsInstanceDao.update(awsInstance);
}
public void waitGetPasswordData(AwsProcessClient awsProcessClient, Long instanceNo) {
AwsInstance awsInstance = awsInstanceDao.read(instanceNo);
String instanceId = awsInstance.getInstanceId();
GetPasswordDataRequest request = new GetPasswordDataRequest();
request.withInstanceId(instanceId);
while (true) {
GetPasswordDataResult result = awsProcessClient.getEc2Client().getPasswordData(request);
if (StringUtils.isNotEmpty(result.getPasswordData())) {
break;
}
try {
Thread.sleep(1000L * awsProcessClient.getDescribeInterval());
} catch (InterruptedException ignore) {
}
}
}
protected Map<String, String> createUserData(Long instanceNo) {
Instance instance = instanceDao.read(instanceNo);
Farm farm = farmDao.read(instance.getFarmNo());
// UserDataを作成
Map<String, String> userData = new HashMap<String, String>();
// DB情報
userData.put("instanceName", instance.getInstanceName());
userData.put("farmName", farm.getFarmName());
// FQDN
String fqdn = instance.getFqdn();
userData.put("hostname", fqdn);
// 初期スクリプト情報
userData.put("scriptserver", Config.getProperty("script.server"));
// DNS情報
userData.putAll(createDnsUserData(instanceNo));
// Puppet情報
userData.putAll(createPuppetUserData(instanceNo));
// VPN情報
Platform platform = platformDao.read(instance.getPlatformNo());
if (BooleanUtils.isNotTrue(platform.getInternal())) {
// 外部のプラットフォームでVPCを利用しない場合、VPN情報を含める
userData.putAll(createVpnUserData(instanceNo));
}
return userData;
}
protected Map<String, String> createDnsUserData(Long instanceNo) {
// UserDataを作成
Map<String, String> userData = new HashMap<String, String>();
// Primary DNSサーバ
userData.put("dns", Config.getProperty("dns.server"));
// Secondry DNSサーバ
String dns2 = Config.getProperty("dns.server2");
if (dns2 != null && dns2.length() > 0) {
userData.put("dns2", dns2);
}
// DNSドメイン
userData.put("dnsdomain", Config.getProperty("dns.domain"));
return userData;
}
protected Map<String, String> createPuppetUserData(Long instanceNo) {
// UserDataを作成
Map<String, String> userData = new HashMap<String, String>();
// PuppetMaster情報
userData.put("puppetmaster", Config.getProperty("puppet.masterHost"));
return userData;
}
protected Map<String, String> createVpnUserData(Long instanceNo) {
// UserDataを作成
Map<String, String> userData = new HashMap<String, String>();
// VPN情報のユーザとパスワードをセットする
Instance instance = instanceDao.read(instanceNo);
userData.put("vpnuser", instance.getFqdn());
userData.put("vpnuserpass", instance.getInstanceCode());
// VPNサーバ情報
userData.put("vpnserver", Config.getProperty("vpn.server"));
userData.put("vpnport", Config.getProperty("vpn.port"));
// ZIPパスワード
userData.put("vpnzippass", Config.getProperty("vpn.zippass"));
// クライアント証明書ダウンロードURL
userData.put("vpnclienturl", Config.getProperty("vpn.clienturl"));
return userData;
}
protected String encodeUserData(Map<String, String> map) {
if (map == null || map.size() == 0) {
return null;
}
StringBuilder sb = new StringBuilder();
for (Entry<String, String> entry : map.entrySet()) {
String key = entry.getKey();
String value = entry.getValue();
if (key != null && value != null) {
sb.append(key).append("=").append(value).append(";");
}
}
sb.delete(sb.length() - 1, sb.length());
// UserDataをエンコード
String userData = sb.toString();
userData = new String(Base64.encodeBase64(userData.getBytes()));
return userData;
}
protected List<BlockDeviceMapping> createBlockDeviceMappings(AwsProcessClient awsProcessClient, ImageAws imageAws,
AwsInstance awsInstance) {
// イメージの取得
com.amazonaws.services.ec2.model.Image image = awsCommonProcess.describeImage(awsProcessClient,
imageAws.getImageId());
if (image == null) {
return null;
}
// EBSイメージでなければBlockDeviceMappingsを設定しない
if (!image.getRootDeviceType().equals(DeviceType.Ebs.toString())) {
return null;
}
List<BlockDeviceMapping> mappings = new ArrayList<BlockDeviceMapping>();
// イメージのBlockDeviceMappingの設定
List<BlockDeviceMapping> imageMappings = createImageBlockDeviceMappings(awsProcessClient, imageAws,
awsInstance, image);
if (imageMappings != null) {
mappings.addAll(imageMappings);
}
// インスタンスストアのBlockDeviceMappingの設定
List<BlockDeviceMapping> instanceStoreMappings = createInstanceStoreBlockDeviceMappings(awsProcessClient,
imageAws, awsInstance, image);
if (instanceStoreMappings != null) {
mappings.addAll(instanceStoreMappings);
}
// 追加のBlockDeviceMappingの設定
List<BlockDeviceMapping> additionalMappings = createAdditionalBlockDeviceMappings(awsProcessClient, imageAws,
awsInstance, image);
if (additionalMappings != null) {
mappings.addAll(additionalMappings);
}
return mappings;
}
protected List<BlockDeviceMapping> createImageBlockDeviceMappings(AwsProcessClient awsProcessClient,
ImageAws imageAws, AwsInstance awsInstance, com.amazonaws.services.ec2.model.Image image) {
// イメージのBlockDeviceMappingを複製する
List<BlockDeviceMapping> mappings = new ArrayList<BlockDeviceMapping>();
for (BlockDeviceMapping originalMapping : image.getBlockDeviceMappings()) {
BlockDeviceMapping mapping = originalMapping.clone();
if (originalMapping.getEbs() != null) {
mapping.withEbs(originalMapping.getEbs().clone());
}
mappings.add(mapping);
}
for (BlockDeviceMapping mapping : mappings) {
if (mapping.getEbs() == null) {
continue;
}
// インスタンス削除時にEBSが削除されるようにする
mapping.getEbs().withDeleteOnTermination(true);
// スナップショットから作る場合、Encryptedは指定できない
if (StringUtils.isNotEmpty(mapping.getEbs().getSnapshotId())) {
mapping.getEbs().withEncrypted(null);
}
// ボリュームタイプを指定する
String volumeType = Config.getProperty("aws.volumeType");
if (StringUtils.isNotEmpty(volumeType)) {
mapping.getEbs().setVolumeType(volumeType);
}
}
// ルートデバイスのボリュームサイズを指定する
if (awsInstance.getRootSize() != null) {
for (BlockDeviceMapping mapping : mappings) {
if (image.getRootDeviceName().equals(mapping.getDeviceName())) {
mapping.getEbs().setVolumeSize(awsInstance.getRootSize());
break;
}
}
}
return mappings;
}
protected List<BlockDeviceMapping> createInstanceStoreBlockDeviceMappings(AwsProcessClient awsProcessClient,
ImageAws imageAws, AwsInstance awsInstance, com.amazonaws.services.ec2.model.Image image) {
int count = AwsInstanceTypeDefinition.getInstanceStoreCount(awsInstance.getInstanceType());
if (count == 0) {
return null;
}
// インスタンスストア数の上限が指定されている場合、その数までに制限する
String maxInstanceStore = Config.getProperty("aws.maxInstanceStore");
if (StringUtils.isNotEmpty(maxInstanceStore)) {
int max = Integer.parseInt(maxInstanceStore);
if (count > max) {
count = max;
}
}
// イメージのBlockDeviceMappingのデバイス名
Set<String> deviceNames = new HashSet<String>();
for (BlockDeviceMapping mapping : image.getBlockDeviceMappings()) {
deviceNames.add(mapping.getDeviceName());
}
List<BlockDeviceMapping> mappings = new ArrayList<BlockDeviceMapping>();
for (int i = 0; i < count; i++) {
String virtualName = "ephemeral" + i;
// イメージのBlockDeviceMappingでインスタンスストアが指定されている場合はスキップする
boolean exist = false;
for (BlockDeviceMapping mapping : image.getBlockDeviceMappings()) {
if (virtualName.equals(mapping.getVirtualName())) {
exist = true;
break;
}
}
if (exist) {
continue;
}
// 空いているデバイス名の識別子を取得
String identifier = null;
for (int j = 0; j < 25; j++) {
char id = (char) ('b' + j);
if (!deviceNames.contains("/dev/sd" + id) && !deviceNames.contains("xvd" + id)) {
identifier = String.valueOf(id);
break;
}
}
if (identifier == null) {
// b から z までの識別子が全て使われている場合は何もしない
continue;
}
String deviceName;
if (StringUtils.equals(image.getPlatform(), PlatformValues.Windows.toString())) {
deviceName = "xvd" + identifier;
} else {
deviceName = "/dev/sd" + identifier;
}
BlockDeviceMapping mapping = new BlockDeviceMapping();
mapping.withVirtualName(virtualName);
mapping.withDeviceName(deviceName);
mappings.add(mapping);
deviceNames.add(deviceName);
}
return mappings;
}
// 拡張用
protected List<BlockDeviceMapping> createAdditionalBlockDeviceMappings(AwsProcessClient awsProcessClient,
ImageAws imageAws, AwsInstance awsInstance, com.amazonaws.services.ec2.model.Image image) {
return null;
}
public void createTag(AwsProcessClient awsProcessClient, Long instanceNo) {
// Eucalyptusの場合はタグを付けない
PlatformAws platformAws = awsProcessClient.getPlatformAws();
if (BooleanUtils.isTrue(platformAws.getEuca())) {
return;
}
Instance instance = instanceDao.read(instanceNo);
AwsInstance awsInstance = awsInstanceDao.read(instanceNo);
User user = userDao.read(awsProcessClient.getUserNo());
Farm farm = farmDao.read(instance.getFarmNo());
// インスタンスにタグを追加する
List<Tag> tags = new ArrayList<Tag>();
tags.add(new Tag("Name", instance.getFqdn()));
tags.add(new Tag("UserName", user.getUsername()));
tags.add(new Tag("CloudName", farm.getDomainName()));
tags.add(new Tag("ServerName", instance.getFqdn()));
awsCommonProcess.createTag(awsProcessClient, awsInstance.getInstanceId(), tags);
com.amazonaws.services.ec2.model.Instance instance2 = awsCommonProcess.describeInstance(awsProcessClient,
awsInstance.getInstanceId());
// EBSにタグを追加する
for (InstanceBlockDeviceMapping mapping : instance2.getBlockDeviceMappings()) {
if (mapping.getEbs() == null) {
continue;
}
String deviceName = mapping.getDeviceName();
if (deviceName.lastIndexOf("/") != -1) {
deviceName = deviceName.substring(deviceName.lastIndexOf("/") + 1);
}
tags = new ArrayList<Tag>();
tags.add(new Tag("Name", instance.getFqdn() + "_" + deviceName));
tags.add(new Tag("UserName", user.getUsername()));
tags.add(new Tag("CloudName", farm.getDomainName()));
tags.add(new Tag("ServerName", instance.getFqdn()));
awsCommonProcess.createTag(awsProcessClient, mapping.getEbs().getVolumeId(), tags);
}
}
public void setAwsCommonProcess(AwsCommonProcess awsCommonProcess) {
this.awsCommonProcess = awsCommonProcess;
}
public void setProcessLogger(ProcessLogger processLogger) {
this.processLogger = processLogger;
}
}