/*
* Copyright 2014 by SCSK Corporation.
*
* 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.api.instance;
import java.util.ArrayList;
import java.util.List;
import javax.ws.rs.GET;
import javax.ws.rs.Path;
import javax.ws.rs.Produces;
import javax.ws.rs.QueryParam;
import javax.ws.rs.core.MediaType;
import jp.primecloud.auto.api.ApiSupport;
import jp.primecloud.auto.api.ApiValidate;
import jp.primecloud.auto.api.response.instance.EditInstanceResponse;
import jp.primecloud.auto.common.status.InstanceStatus;
import jp.primecloud.auto.entity.crud.AwsAddress;
import jp.primecloud.auto.entity.crud.CloudstackInstance;
import jp.primecloud.auto.entity.crud.Image;
import jp.primecloud.auto.entity.crud.ImageAws;
import jp.primecloud.auto.entity.crud.ImageAzure;
import jp.primecloud.auto.entity.crud.ImageCloudstack;
import jp.primecloud.auto.entity.crud.ImageOpenstack;
import jp.primecloud.auto.entity.crud.ImageVcloud;
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.PlatformAzure;
import jp.primecloud.auto.entity.crud.User;
import jp.primecloud.auto.entity.crud.VcloudInstance;
import jp.primecloud.auto.exception.AutoApplicationException;
import jp.primecloud.auto.service.dto.InstanceNetworkDto;
import jp.primecloud.auto.service.dto.KeyPairDto;
import jp.primecloud.auto.service.dto.SecurityGroupDto;
import jp.primecloud.auto.service.dto.StorageTypeDto;
import jp.primecloud.auto.service.dto.SubnetDto;
import jp.primecloud.auto.service.dto.ZoneDto;
import jp.primecloud.auto.util.IpAddressUtils;
import org.apache.commons.lang.StringUtils;
@Path("/EditInstance")
@Deprecated
public class EditInstance extends ApiSupport {
/**
* サーバ編集
*
* @param instanceNo インスタンス番号
* @param instanceType インスタンスタイプ
* @param keyName キーペア名(AWSのみ)
* @param securityGroups セキュリティグループ(AWSのみ)
* @param availabilityZone ゾーン(AWSのみ)
* @param ipAddress 固定IPアドレス(AWS、VCloudのみ)
* @param cidrBlock シダーブロック(サブネット)(cidrBlock)(EC2+VPCのみ)
* @param privateIp プライベートIP(EC2+VPCのみ)
* @param comment コメント
* @param storageType ストレージタイプ(VCLOUDのみ)
* @return EditInstanceResponse
*/
@GET
@Produces(MediaType.APPLICATION_JSON)
public EditInstanceResponse editInstance(@QueryParam(PARAM_NAME_INSTANCE_NO) String instanceNo,
@QueryParam(PARAM_NAME_INSTANCE_TYPE) String instanceType, @QueryParam(PARAM_NAME_KEY_NAME) String keyName,
@QueryParam(PARAM_NAME_SECURITY_GROUPS) String securityGroups,
@QueryParam(PARAM_NAME_AVAILABILITY_ZONE) String availabilityZone,
@QueryParam(PARAM_NAME_IP_ADDRESS) String ipAddress, @QueryParam(PARAM_NAME_SUBNET) String cidrBlock,
@QueryParam(PARAM_NAME_PRIVATE_IP) String privateIp, @QueryParam(PARAM_NAME_COMMENT) String comment,
@QueryParam(PARAM_NAME_STORAGE_TYPE) String storageType) {
// InstanceNo
ApiValidate.validateInstanceNo(instanceNo);
//インスタンス取得
Instance instance = getInstance(Long.parseLong(instanceNo));
// 権限チェック
User user = checkAndGetUser(instance);
// インスタンスのステータスチェック
InstanceStatus status = InstanceStatus.fromStatus(instance.getStatus());
if (InstanceStatus.STOPPED != status) {
// インスタンスが停止済み以外
throw new AutoApplicationException("EAPI-100014", instanceNo);
}
//プラットフォーム取得
Platform platform = platformDao.read(instance.getPlatformNo());
if (platform == null) {
// プラットフォームが存在しない
throw new AutoApplicationException("EAPI-100000", "Platform", PARAM_NAME_PLATFORM_NO,
instance.getPlatformNo());
}
// プラットフォーム種別チェック
if (!PLATFORM_TYPE_AWS.equals(platform.getPlatformType())
&& !PLATFORM_TYPE_CLOUDSTACK.equals(platform.getPlatformType())
&& !PLATFORM_TYPE_VCLOUD.equals(platform.getPlatformType())
&& !PLATFORM_TYPE_OPENSTACK.equals(platform.getPlatformType())
&& !PLATFORM_TYPE_AZURE.equals(platform.getPlatformType())) {
//プラットフォームがAws、CloudStack、VCloud、OpenStack、Azure以外
throw new AutoApplicationException("EAPI-100031", "EC2 or CloudStack or VCloud or OpenStack or Azure",
instance.getInstanceNo(), instance.getPlatformNo());
}
// イメージ取得
Image image = imageDao.read(instance.getImageNo());
if (image == null || image.getPlatformNo().equals(instance.getPlatformNo()) == false) {
// イメージが存在しない
throw new AutoApplicationException("EAPI-100000", "Image", PARAM_NAME_IMAGE_NO, instance.getImageNo());
}
if (PLATFORM_TYPE_AWS.equals(platform.getPlatformType())) {
editAwsInstance(user.getUserNo(), instance, instanceType, keyName, securityGroups, cidrBlock,
availabilityZone, ipAddress, privateIp, comment);
} else if (PLATFORM_TYPE_CLOUDSTACK.equals(platform.getPlatformType())) {
editCloudstackInstance(user.getUserNo(), instance, instanceType, keyName, comment);
} else if (PLATFORM_TYPE_VCLOUD.equals(platform.getPlatformType())) {
editVcloudInstance(user.getUserNo(), instance, instanceType, storageType, keyName, comment);
} else if (PLATFORM_TYPE_OPENSTACK.equals(platform.getPlatformType())) {
editOpenstackInstance(user.getUserNo(), instance, instanceType, keyName, securityGroups, availabilityZone,
comment);
} else if (PLATFORM_TYPE_AZURE.equals(platform.getPlatformType())) {
editAzureInstance(user.getUserNo(), instance, instanceType, cidrBlock, availabilityZone, comment);
}
EditInstanceResponse response = new EditInstanceResponse();
return response;
}
private void editAwsInstance(Long userNo, Instance instance, String instanceType, String keyName,
String securityGroups, String cidrBlock, String availabilityZone, String ipAddress, String privateIp,
String comment) {
PlatformAws platformAws = platformAwsDao.read(instance.getPlatformNo());
// InstanceType
ApiValidate.validateInstanceType(instanceType, true);
ImageAws imageAws = imageAwsDao.read(instance.getImageNo());
if (commaTextToList(imageAws.getInstanceTypes()).contains(instanceType) == false) {
// インスタンスタイプがイメージのインスタンスタイプに含まれていない
throw new AutoApplicationException("EAPI-000011", imageAws.getImageNo(), instanceType);
}
// KeyName
ApiValidate.validateKeyName(keyName);
if (checkKeyName(userNo, instance.getPlatformNo(), keyName) == false) {
// キーペアがプラットフォームに存在しない
throw new AutoApplicationException("EAPI-000012", instance.getPlatformNo(), keyName);
}
// SecurityGroups(AWSのみ)
ApiValidate.validateSecurityGroups(securityGroups);
if (checkSecurityGroups(userNo, instance.getPlatformNo(), platformAws.getVpcId(), securityGroups) == false) {
//プラットフォームにセキュリティグループが存在しない
throw new AutoApplicationException("EAPI-100019", instance.getPlatformNo(), securityGroups);
}
// Subnet(VPCのみ)
String subnetId = null;
if (platformAws.getVpc()) {
//必須チェック
ApiValidate.validateSubnet(cidrBlock);
SubnetDto subnetDto = getSubnet(userNo, instance.getPlatformNo(), platformAws.getVpcId(), cidrBlock);
if (subnetDto == null) {
//サブネットがプラットフォームに存在しない
throw new AutoApplicationException("EAPI-000017", instance.getPlatformNo(), cidrBlock);
}
subnetId = subnetDto.getSubnetId();
availabilityZone = subnetDto.getZoneid();
} else {
subnetId = null;
}
//PrivateIpAddress(VPCのみ)
if (platformAws.getVpc() && StringUtils.isNotEmpty(subnetId) && StringUtils.isNotEmpty(privateIp)) {
//書式チェック
ApiValidate.validatePrivateIpAddress(privateIp);
//サブネット内、有効IPチェック
if (checkPrivateIp(cidrBlock, privateIp) == false) {
//サブネット内で有効なIPではない
throw new AutoApplicationException("EAPI-000018", cidrBlock, privateIp);
}
} else {
privateIp = null;
}
//AvailabilityZoneName
if (platformAws.getVpc() == false) {
//VPCではない場合
//※VPCの場合はサブネットでゾーンが決まるので、入力チェックは行わない
ApiValidate.validateAvailabilityZone(availabilityZone);
if (StringUtils.isNotEmpty(availabilityZone)
&& checkAvailabilityZoneName(userNo, instance.getPlatformNo(), availabilityZone) == false) {
// AvailabilityZoneName がプラットフォームに存在しない
throw new AutoApplicationException("EAPI-100017", instance.getPlatformNo(), availabilityZone);
}
}
//IpAddress(ElasticIp)
Long ipAddressNo = null;
ApiValidate.validateIpAddress(ipAddress, false);
if (StringUtils.isNotEmpty(ipAddress)) {
List<AwsAddress> awsAddresses = awsAddressDao.readByUserNo(userNo);
for (AwsAddress awsAddress : awsAddresses) {
if (instance.getPlatformNo().equals(awsAddress.getPlatformNo())) {
if (ipAddress.equals(awsAddress.getPublicIp())) {
ipAddressNo = awsAddress.getAddressNo();
break;
}
}
}
if (ipAddressNo == null) {
// IPAddressがDBに存在しない場合
throw new AutoApplicationException("EAPI-100016", instance.getInstanceNo(), ipAddress);
}
}
// Comment
ApiValidate.validateComment(comment);
// 更新処理
instanceService.updateAwsInstance(instance.getInstanceNo(), instance.getInstanceName(), comment, keyName,
instanceType, securityGroups, availabilityZone, ipAddressNo, subnetId, null, privateIp);
}
private void editCloudstackInstance(Long userNo, Instance instance, String instanceType, String keyName,
String comment) {
CloudstackInstance cloudstackInstance = cloudstackInstanceDao.read(instance.getInstanceNo());
if (cloudstackInstance == null) {
// CloudStackInstanceが存在しない
throw new AutoApplicationException("EAPI-100000", "CloudStackInstance", PARAM_NAME_INSTANCE_NO,
instance.getInstanceNo());
}
// InstanceType
ApiValidate.validateInstanceType(instanceType, true);
ImageCloudstack imageCloudstack = imageCloudstackDao.read(instance.getImageNo());
if (commaTextToList(imageCloudstack.getInstanceTypes()).contains(instanceType) == false) {
// インスタンスタイプがイメージのインスタンスタイプに含まれていない
throw new AutoApplicationException("EAPI-000011", imageCloudstack.getImageNo(), instanceType);
}
// KeyName
if (StringUtils.isNotEmpty(keyName)) {
if (checkKeyName(userNo, instance.getPlatformNo(), keyName) == false) {
// キーペアがプラットフォームに存在しない
throw new AutoApplicationException("EAPI-000012", instance.getPlatformNo(), keyName);
}
}
// Comment
ApiValidate.validateComment(comment);
//更新処理
instanceService.updateCloudstackInstance(instance.getInstanceNo(), instance.getInstanceName(), comment,
keyName, instanceType, cloudstackInstance.getSecuritygroup(), cloudstackInstance.getZoneid(), null);
}
private void editVcloudInstance(Long userNo, Instance instance, String instanceType, String storageType,
String keyName, String comment) {
VcloudInstance vcloudInstance = vcloudInstanceDao.read(instance.getInstanceNo());
if (vcloudInstance == null) {
// VcloudInstanceが存在しない
throw new AutoApplicationException("EAPI-100000", "VcloudInstance", PARAM_NAME_INSTANCE_NO,
instance.getInstanceNo());
}
// InstanceType
ApiValidate.validateInstanceType(instanceType, true);
ImageVcloud imageVcloud = imageVcloudDao.read(instance.getImageNo());
if (commaTextToList(imageVcloud.getInstanceTypes()).contains(instanceType) == false) {
// インスタンスタイプがイメージのインスタンスタイプに含まれていない
throw new AutoApplicationException("EAPI-000011", imageVcloud.getImageNo(), instanceType);
}
// StorageType
Long storageTypeNo = null;
ApiValidate.validateStrageType(storageType);
storageTypeNo = checkStorageType(userNo, instance.getPlatformNo(), storageType);
if (storageTypeNo == null) {
// ストレージタイプがプラットフォームに存在しない
throw new AutoApplicationException("EAPI-000022", instance.getPlatformNo(), storageType);
}
// KeyName
Long keyNo = null;
ApiValidate.validateKeyName(keyName);
keyNo = checkVcloudKeyName(userNo, instance.getPlatformNo(), keyName);
if (keyNo == null) {
// キーペアがプラットフォームに存在しない
throw new AutoApplicationException("EAPI-000012", instance.getPlatformNo(), keyName);
}
// Comment
ApiValidate.validateComment(comment);
// TODO ネットワーク追加、ディスクの追加未対応
List<InstanceNetworkDto> instanceNetworks = new ArrayList<InstanceNetworkDto>();
//更新処理
instanceService.updateVcloudInstance(instance.getInstanceNo(), instance.getInstanceName(), comment,
storageTypeNo, keyNo, instanceType, instanceNetworks);
}
private void editOpenstackInstance(Long userNo, Instance instance, String instanceType, String keyName,
String securityGroups, String availabilityZone, String comment) {
// InstanceType
ApiValidate.validateInstanceType(instanceType, true);
ImageOpenstack imageOpenstack = imageOpenstackDao.read(instance.getImageNo());
if (commaTextToList(imageOpenstack.getInstanceTypes()).contains(instanceType) == false) {
// インスタンスタイプがイメージのインスタンスタイプに含まれていない
throw new AutoApplicationException("EAPI-000011", imageOpenstack.getImageNo(), instanceType);
}
// KeyName
ApiValidate.validateKeyName(keyName);
if (checkKeyName(userNo, instance.getPlatformNo(), keyName) == false) {
// キーペアがプラットフォームに存在しない
throw new AutoApplicationException("EAPI-000012", instance.getPlatformNo(), keyName);
}
// SecurityGroups
ApiValidate.validateSecurityGroups(securityGroups);
if (checkSecurityGroups(userNo, instance.getPlatformNo(), null, securityGroups) == false) {
//プラットフォームにセキュリティグループが存在しない
throw new AutoApplicationException("EAPI-100019", instance.getPlatformNo(), securityGroups);
}
//AvailabilityZone
ApiValidate.validateAvailabilityZone(availabilityZone);
if (StringUtils.isNotEmpty(availabilityZone)
&& checkAvailabilityZoneName(userNo, instance.getPlatformNo(), availabilityZone) == false) {
// AvailabilityZone がプラットフォームに存在しない
throw new AutoApplicationException("EAPI-100017", instance.getPlatformNo(), availabilityZone);
}
// Comment
ApiValidate.validateComment(comment);
// 更新処理
instanceService.updateOpenStackInstance(instance.getInstanceNo(), instance.getInstanceName(), comment,
instanceType, availabilityZone, securityGroups, keyName);
}
private void editAzureInstance(Long userNo, Instance instance, String instanceType, String cidrBlock,
String availabilitySet, String comment) {
PlatformAzure platformAzure = platformAzureDao.read(instance.getPlatformNo());
// InstanceType
ApiValidate.validateInstanceType(instanceType, true);
ImageAzure imageAzure = imageAzureDao.read(instance.getImageNo());
if (commaTextToList(imageAzure.getInstanceTypes()).contains(instanceType) == false) {
// インスタンスタイプがイメージのインスタンスタイプに含まれていない
throw new AutoApplicationException("EAPI-000011", imageAzure.getImageNo(), instanceType);
}
//AvailabilitySet
ApiValidate.validateAvailabilityZone(availabilitySet);
if (StringUtils.isNotEmpty(availabilitySet)) {
String[] availabilitySets = platformAzure.getAvailabilitySets().split(",");
boolean existFlg = false;
for (int i = 0; i <= availabilitySets.length; i++) {
if (availabilitySet.equals(availabilitySets[i])) {
existFlg = true;
}
}
if (!existFlg) {
// AvailabilitySet がプラットフォームに存在しない
throw new AutoApplicationException("EAPI-100017", instance.getPlatformNo(), availabilitySet);
}
}
// Subnet
String subnetId = null;
ApiValidate.validateSubnet(cidrBlock);
SubnetDto subnetDto = getAzureSubnet(userNo, instance.getPlatformNo(), platformAzure.getNetworkName(),
cidrBlock);
if (subnetDto == null) {
//サブネットがプラットフォームに存在しない
throw new AutoApplicationException("EAPI-000017", instance.getPlatformNo(), cidrBlock);
}
subnetId = subnetDto.getSubnetId();
// Comment
ApiValidate.validateComment(comment);
//更新処理
instanceService.updateAzureInstance(instance.getInstanceNo(), instance.getInstanceName(), comment,
instanceType, availabilitySet, subnetId);
}
private Long checkStorageType(Long userNo, Long platformNo, String storageTypeName) {
// ストレージタイプの名称がプラットフォームに存在するかチェック
List<StorageTypeDto> storageTypes = iaasDescribeService.getStorageTypes(userNo, platformNo);
for (StorageTypeDto storageType : storageTypes) {
if (StringUtils.equals(storageTypeName, storageType.getStorageTypeName())) {
return storageType.getStorageTypeNo();
}
}
return null;
}
private boolean checkKeyName(Long userNo, Long platformNo, String keyName) {
// キーペアの名称がプラットフォームに存在するかチェック
//Aws or Eucalyptus or CloudStack
List<KeyPairDto> keyPairs = iaasDescribeService.getKeyPairs(userNo, platformNo);
for (KeyPairDto keyPair : keyPairs) {
if (StringUtils.equals(keyName, keyPair.getKeyName())) {
return true;
}
}
return false;
}
private Long checkVcloudKeyName(Long userNo, Long platformNo, String keyName) {
// キーペアの名称がプラットフォームに存在するかチェック
//VCloud
List<KeyPairDto> keyPairs = iaasDescribeService.getKeyPairs(userNo, platformNo);
for (KeyPairDto keyPair : keyPairs) {
if (StringUtils.equals(keyName, keyPair.getKeyName())) {
return keyPair.getKeyNo();
}
}
return null;
}
private boolean checkSecurityGroups(Long userNo, Long platformNo, String vpcId, String securityGroups) {
boolean isContain = false;
if (StringUtils.isNotEmpty(securityGroups)) {
List<String> groupNames = getSecurityGroupNames(userNo, platformNo, vpcId);
for (String grouName : securityGroups.split(",")) {
if (groupNames.contains(grouName.trim())) {
isContain = true;
} else {
return false;
}
}
}
return isContain;
}
private List<String> getSecurityGroupNames(Long userNo, Long platformNo, String vpcId) {
List<String> groupNames = new ArrayList<String>();
List<SecurityGroupDto> securityGroupDtos = iaasDescribeService.getSecurityGroups(userNo, platformNo, vpcId);
for (SecurityGroupDto dto : securityGroupDtos) {
groupNames.add(dto.getGroupName());
}
return groupNames;
}
private boolean checkAvailabilityZoneName(Long userNo, Long platformNo, String zoneName) {
List<ZoneDto> zones = iaasDescribeService.getAvailabilityZones(userNo, platformNo);
for (ZoneDto zone : zones) {
if (StringUtils.equals(zoneName, zone.getZoneName())) {
return true;
}
}
return false;
}
private SubnetDto getSubnet(Long userNo, Long platformNo, String vpcId, String cidrBlock) {
List<SubnetDto> subnets = iaasDescribeService.getSubnets(userNo, platformNo, vpcId);
for (SubnetDto subnetDto : subnets) {
if (subnetDto.getCidrBlock().equals(cidrBlock)) {
return subnetDto;
}
}
return null;
}
private SubnetDto getAzureSubnet(Long userNo, Long platformNo, String networkName, String cidrBlock) {
List<SubnetDto> subnets = iaasDescribeService.getAzureSubnets(userNo, platformNo, networkName);
for (SubnetDto subnetDto : subnets) {
if (subnetDto.getCidrBlock().equals(cidrBlock)) {
return subnetDto;
}
}
return null;
}
private boolean checkPrivateIp(String cidrBlock, String privateIp) {
long privateIpAddress = IpAddressUtils.parse(privateIp);
long networkAddress = IpAddressUtils.getNetworkAddress(cidrBlock);
long broadcastAddress = IpAddressUtils.getBroadcastAddress(cidrBlock);
// AWSのサブネットの最初の4つと最後の1つのIPアドレスは予約されているため使用できない
if (privateIpAddress < networkAddress + 4 || broadcastAddress - 1 < privateIpAddress) {
return false;
}
return true;
}
private static List<String> commaTextToList(String commaText) {
List<String> list = new ArrayList<String>();
if (StringUtils.isNotEmpty(commaText)) {
for (String splitStr : StringUtils.split(commaText, ",")) {
list.add(splitStr.trim());
}
}
return list;
}
}