diff --git a/api/src/com/cloud/api/commands/CreateAccountCmd.java b/api/src/com/cloud/api/commands/CreateAccountCmd.java index bf62b00ea56..ec613d77c29 100644 --- a/api/src/com/cloud/api/commands/CreateAccountCmd.java +++ b/api/src/com/cloud/api/commands/CreateAccountCmd.java @@ -67,6 +67,9 @@ public class CreateAccountCmd extends BaseCmd { @Parameter(name=ApiConstants.USERNAME, type=CommandType.STRING, required=true, description="Unique username.") private String username; + + @Parameter(name=ApiConstants.NETWORK_DOMAIN, type=CommandType.STRING, description="Network domain for the account's networks") + private String networkDomain; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -107,6 +110,10 @@ public class CreateAccountCmd extends BaseCmd { public String getUsername() { return username; } + + public String getNetworkDomain() { + return networkDomain; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/com/cloud/api/commands/CreateDomainCmd.java b/api/src/com/cloud/api/commands/CreateDomainCmd.java index 2b50d86c54a..1ca6fd4d4f9 100644 --- a/api/src/com/cloud/api/commands/CreateDomainCmd.java +++ b/api/src/com/cloud/api/commands/CreateDomainCmd.java @@ -45,6 +45,8 @@ public class CreateDomainCmd extends BaseCmd { @Parameter(name=ApiConstants.PARENT_DOMAIN_ID, type=CommandType.LONG, description="assigns new domain a parent domain by domain ID of the parent. If no parent domain is specied, the ROOT domain is assumed.") private Long parentDomainId; + @Parameter(name=ApiConstants.NETWORK_DOMAIN, type=CommandType.STRING, description="Network domain for networks in the domain") + private String networkDomain; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -58,6 +60,9 @@ public class CreateDomainCmd extends BaseCmd { return parentDomainId; } + public String getNetworkDomain() { + return networkDomain; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/com/cloud/api/commands/CreateZoneCmd.java b/api/src/com/cloud/api/commands/CreateZoneCmd.java index 049245dcb5b..3388427d39b 100644 --- a/api/src/com/cloud/api/commands/CreateZoneCmd.java +++ b/api/src/com/cloud/api/commands/CreateZoneCmd.java @@ -60,7 +60,7 @@ public class CreateZoneCmd extends BaseCmd { @Parameter(name=ApiConstants.VLAN, type=CommandType.STRING, description="the VLAN for the Zone") private String vlan; - @Parameter(name=ApiConstants.DOMAIN, type=CommandType.STRING, description="Domain name for the Vms in the zone") + @Parameter(name=ApiConstants.DOMAIN, type=CommandType.STRING, description="Network domain name for the networks in the zone") private String domain; @Parameter(name=ApiConstants.DOMAIN_ID, type=CommandType.LONG, description="the ID of the containing domain, null for public zones") diff --git a/api/src/com/cloud/api/commands/UpdateAccountCmd.java b/api/src/com/cloud/api/commands/UpdateAccountCmd.java index 165d586963f..05a77d60ab1 100644 --- a/api/src/com/cloud/api/commands/UpdateAccountCmd.java +++ b/api/src/com/cloud/api/commands/UpdateAccountCmd.java @@ -44,6 +44,9 @@ public class UpdateAccountCmd extends BaseCmd{ @Parameter(name=ApiConstants.NEW_NAME, type=CommandType.STRING, required=true, description="new name for the account") private String newName; + + @Parameter(name=ApiConstants.NETWORK_DOMAIN, type=CommandType.STRING, description="Network domain for the account's networks") + private String networkDomain; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -60,6 +63,10 @@ public class UpdateAccountCmd extends BaseCmd{ public String getNewName() { return newName; } + + public String getNetworkDomain() { + return networkDomain; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/com/cloud/api/commands/UpdateDomainCmd.java b/api/src/com/cloud/api/commands/UpdateDomainCmd.java index cb0a2ba2e34..4af4daa771a 100644 --- a/api/src/com/cloud/api/commands/UpdateDomainCmd.java +++ b/api/src/com/cloud/api/commands/UpdateDomainCmd.java @@ -43,6 +43,9 @@ public class UpdateDomainCmd extends BaseCmd { @Parameter(name=ApiConstants.NAME, type=CommandType.STRING, description="updates domain with this name") private String domainName; + + @Parameter(name=ApiConstants.NETWORK_DOMAIN, type=CommandType.STRING, description="Network domain for the domain's networks") + private String networkDomain; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -55,6 +58,10 @@ public class UpdateDomainCmd extends BaseCmd { public String getDomainName() { return domainName; } + + public String getNetworkDomain() { + return networkDomain; + } ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// diff --git a/api/src/com/cloud/api/commands/UpdateZoneCmd.java b/api/src/com/cloud/api/commands/UpdateZoneCmd.java index 0c40b0cb583..e276cb3c5b8 100644 --- a/api/src/com/cloud/api/commands/UpdateZoneCmd.java +++ b/api/src/com/cloud/api/commands/UpdateZoneCmd.java @@ -27,7 +27,6 @@ import com.cloud.api.BaseCmd; import com.cloud.api.Implementation; import com.cloud.api.Parameter; import com.cloud.api.ServerApiException; -import com.cloud.api.BaseCmd.CommandType; import com.cloud.api.response.ZoneResponse; import com.cloud.dc.DataCenter; import com.cloud.user.Account; @@ -76,7 +75,10 @@ public class UpdateZoneCmd extends BaseCmd { private Map details; @Parameter(name=ApiConstants.DHCP_PROVIDER, type=CommandType.STRING, description="the dhcp Provider for the Zone") - private String dhcpProvider; + private String dhcpProvider; + + @Parameter(name=ApiConstants.DOMAIN, type=CommandType.STRING, description="Network domain name for the networks in the zone") + private String domain; ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// @@ -128,12 +130,16 @@ public class UpdateZoneCmd extends BaseCmd { public String getDhcpProvider() { return dhcpProvider; - } + } + + public String getDomain() { + return domain; + } + ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// - @Override public String getCommandName() { return s_name; diff --git a/api/src/com/cloud/api/response/AccountResponse.java b/api/src/com/cloud/api/response/AccountResponse.java index bb4d4d7f714..690c0b01ec1 100644 --- a/api/src/com/cloud/api/response/AccountResponse.java +++ b/api/src/com/cloud/api/response/AccountResponse.java @@ -104,6 +104,9 @@ public class AccountResponse extends BaseResponse { @SerializedName("user") @Param(description="the list of users associated with account", responseObject = UserResponse.class) private List users; + + @SerializedName(ApiConstants.NETWORK_DOMAIN) @Param(description="the network domain") + private String networkDomain; public Long getId() { return id; @@ -320,4 +323,9 @@ public class AccountResponse extends BaseResponse { public void setUsers(List users) { this.users = users; } + + public void setNetworkDomain(String networkDomain) { + this.networkDomain = networkDomain; + } + } diff --git a/api/src/com/cloud/api/response/DomainResponse.java b/api/src/com/cloud/api/response/DomainResponse.java index 420d0dbd478..f1242705b71 100644 --- a/api/src/com/cloud/api/response/DomainResponse.java +++ b/api/src/com/cloud/api/response/DomainResponse.java @@ -39,6 +39,9 @@ public class DomainResponse extends BaseResponse { @SerializedName("haschild") @Param(description="whether the domain has one or more sub-domains") private boolean hasChild; + + @SerializedName(ApiConstants.NETWORK_DOMAIN) @Param(description="the network domain") + private String networkDomain; public Long getId() { return id; @@ -87,4 +90,9 @@ public class DomainResponse extends BaseResponse { public void setHasChild(boolean hasChild) { this.hasChild = hasChild; } + + public void setNetworkDomain(String networkDomain) { + this.networkDomain = networkDomain; + } + } diff --git a/api/src/com/cloud/api/response/NetworkResponse.java b/api/src/com/cloud/api/response/NetworkResponse.java index 7ada9138425..528f119d057 100644 --- a/api/src/com/cloud/api/response/NetworkResponse.java +++ b/api/src/com/cloud/api/response/NetworkResponse.java @@ -110,7 +110,7 @@ public class NetworkResponse extends BaseResponse{ @SerializedName("service") @Param(description="the list of services", responseObject = ServiceResponse.class) private List services; - @SerializedName("networkdomain") @Param(description="the network domain") + @SerializedName(ApiConstants.NETWORK_DOMAIN) @Param(description="the network domain") private String networkDomain; @SerializedName(ApiConstants.SECURITY_GROUP_EANBLED) @Param(description="true if security group is enabled, false otherwise") diff --git a/api/src/com/cloud/api/response/ZoneResponse.java b/api/src/com/cloud/api/response/ZoneResponse.java index 59288a20dbf..a7579119be8 100644 --- a/api/src/com/cloud/api/response/ZoneResponse.java +++ b/api/src/com/cloud/api/response/ZoneResponse.java @@ -56,7 +56,7 @@ public class ZoneResponse extends BaseResponse { @SerializedName(ApiConstants.DISPLAY_TEXT) @Param(description="the display text of the zone") private String displayText; - @SerializedName(ApiConstants.DOMAIN) @Param(description="Domain name for the Vms in the zone") + @SerializedName(ApiConstants.DOMAIN) @Param(description="Network domain name for the networks in the zone") private String domain; @SerializedName(ApiConstants.DOMAIN_ID) @Param(description="the ID of the containing domain, null for public zones") diff --git a/api/src/com/cloud/domain/Domain.java b/api/src/com/cloud/domain/Domain.java index 57219733aa7..fc27974f374 100644 --- a/api/src/com/cloud/domain/Domain.java +++ b/api/src/com/cloud/domain/Domain.java @@ -58,4 +58,6 @@ public interface Domain extends OwnedBy { State getState(); void setState(State state); + + String getNetworkDomain(); } diff --git a/api/src/com/cloud/user/Account.java b/api/src/com/cloud/user/Account.java index 1fe9d9242d1..1a89cf05b3f 100755 --- a/api/src/com/cloud/user/Account.java +++ b/api/src/com/cloud/user/Account.java @@ -53,4 +53,5 @@ public interface Account extends ControlledEntity { public short getType(); public State getState(); public Date getRemoved(); + public String getNetworkDomain(); } diff --git a/core/src/com/cloud/user/AccountVO.java b/core/src/com/cloud/user/AccountVO.java index a02ba91b859..fdcdb214702 100644 --- a/core/src/com/cloud/user/AccountVO.java +++ b/core/src/com/cloud/user/AccountVO.java @@ -57,6 +57,9 @@ public class AccountVO implements Account { @Column(name="cleanup_needed") private boolean needsCleanup = false; + + @Column(name="network_domain") + private String networkDomain; public AccountVO() {} @@ -126,5 +129,15 @@ public class AccountVO implements Account { @Override public String toString() { return new StringBuilder("Acct[").append(id).append("-").append(accountName).append("]").toString(); - } + } + + @Override + public String getNetworkDomain() { + return networkDomain; + } + + public void setNetworkDomain(String networkDomain) { + this.networkDomain = networkDomain; + } + } diff --git a/server/src/com/cloud/api/ApiResponseHelper.java b/server/src/com/cloud/api/ApiResponseHelper.java index b2581ebbcfe..bb99d12a3e9 100755 --- a/server/src/com/cloud/api/ApiResponseHelper.java +++ b/server/src/com/cloud/api/ApiResponseHelper.java @@ -223,6 +223,7 @@ public class ApiResponseHelper implements ResponseGenerator { accountResponse.setDomainId(account.getDomainId()); accountResponse.setDomainName(ApiDBUtils.findDomainById(account.getDomainId()).getName()); accountResponse.setState(account.getState().toString()); + accountResponse.setNetworkDomain(account.getNetworkDomain()); // get network stat List stats = ApiDBUtils.listUserStatsBy(account.getId()); @@ -343,6 +344,7 @@ public class ApiResponseHelper implements ResponseGenerator { domainResponse.setDomainName(domain.getName()); domainResponse.setId(domain.getId()); domainResponse.setLevel(domain.getLevel()); + domainResponse.setNetworkDomain(domain.getNetworkDomain()); domainResponse.setParentDomainId(domain.getParent()); if (domain.getParent() != null) { domainResponse.setParentDomainName(ApiDBUtils.findDomainById(domain.getParent()).getName()); diff --git a/server/src/com/cloud/configuration/ConfigurationManager.java b/server/src/com/cloud/configuration/ConfigurationManager.java index a18635db698..ca43e348081 100644 --- a/server/src/com/cloud/configuration/ConfigurationManager.java +++ b/server/src/com/cloud/configuration/ConfigurationManager.java @@ -112,11 +112,12 @@ public interface ConfigurationManager extends ConfigurationService, Manager { * @param guestCidr * @param zoneType * @param allocationState + * @param networkDomain TODO * @return * @throws * @throws */ - DataCenterVO createZone(long userId, String zoneName, String dns1, String dns2, String internalDns1, String internalDns2, String vnetRange, String guestCidr, String domain, Long domainId, NetworkType zoneType, boolean isSecurityGroupEnabled, String allocationState); + DataCenterVO createZone(long userId, String zoneName, String dns1, String dns2, String internalDns1, String internalDns2, String vnetRange, String guestCidr, String domain, Long domainId, NetworkType zoneType, boolean isSecurityGroupEnabled, String allocationState, String networkDomain); /** * Deletes a VLAN from the database, along with all of its IP addresses. Will not delete VLANs that have allocated IP addresses. diff --git a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java index e52f1d55e90..65ca15236e0 100755 --- a/server/src/com/cloud/configuration/ConfigurationManagerImpl.java +++ b/server/src/com/cloud/configuration/ConfigurationManagerImpl.java @@ -1094,6 +1094,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura String allocationStateStr = cmd.getAllocationState(); String dhcpProvider = cmd.getDhcpProvider(); Map detailsMap = cmd.getDetails(); + String networkDomain = cmd.getDomain(); Map newDetails = new HashMap(); if (detailsMap != null) { @@ -1206,6 +1207,17 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura if (guestCidr == null) { guestCidr = zone.getGuestNetworkCidr(); } + + //validate network domain + if (networkDomain != null) { + if (!NetUtils.verifyDomainName(networkDomain)) { + throw new InvalidParameterValueException( + "Invalid network domain. Total length shouldn't exceed 190 chars. Each domain label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + + "and the hyphen ('-'); can't start or end with \"-\""); + } + } else { + networkDomain = zone.getDomain(); + } boolean checkForDuplicates = !zoneName.equals(oldZoneName); checkZoneParameters(zoneName, dns1, dns2, internalDns1, internalDns2, checkForDuplicates, null, allocationStateStr);// not @@ -1225,6 +1237,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura zone.setInternalDns1(internalDns1); zone.setInternalDns2(internalDns2); zone.setGuestNetworkCidr(guestCidr); + zone.setDomain(networkDomain); if (vnetRange != null) { zone.setVnet(vnetRange); @@ -1272,7 +1285,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura @Override @DB public DataCenterVO createZone(long userId, String zoneName, String dns1, String dns2, String internalDns1, String internalDns2, String vnetRange, String guestCidr, String domain, Long domainId, - NetworkType zoneType, boolean isSecurityGroupEnabled, String allocationStateStr) { + NetworkType zoneType, boolean isSecurityGroupEnabled, String allocationStateStr, String networkDomain) { int vnetStart = 0; int vnetEnd = 0; if (vnetRange != null) { @@ -1299,6 +1312,15 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura if ((guestCidr != null) && !NetUtils.validateGuestCidr(guestCidr)) { throw new InvalidParameterValueException("Please enter a valid guest cidr"); } + + //Validate network domain + if (networkDomain != null) { + if (!NetUtils.verifyDomainName(networkDomain)) { + throw new InvalidParameterValueException( + "Invalid network domain. Total length shouldn't exceed 190 chars. Each domain label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + + "and the hyphen ('-'); can't start or end with \"-\""); + } + } checkZoneParameters(zoneName, dns1, dns2, internalDns1, internalDns2, true, domainId, allocationStateStr); @@ -1308,7 +1330,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura try { txn.start(); // Create the new zone in the database - DataCenterVO zone = new DataCenterVO(zoneName, null, dns1, dns2, internalDns1, internalDns2, vnetRange, guestCidr, domain, domainId, zoneType, isSecurityGroupEnabled, zoneToken); + DataCenterVO zone = new DataCenterVO(zoneName, null, dns1, dns2, internalDns1, internalDns2, vnetRange, guestCidr, domain, domainId, zoneType, isSecurityGroupEnabled, zoneToken, networkDomain); if (allocationStateStr != null && !allocationStateStr.isEmpty()) { Grouping.AllocationState allocationState = Grouping.AllocationState.valueOf(allocationStateStr); zone.setAllocationState(allocationState); @@ -1336,6 +1358,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura @Override public void createDefaultNetworks(long zoneId, boolean isSecurityGroupEnabled) throws ConcurrentOperationException { DataCenterVO zone = _zoneDao.findById(zoneId); + String networkDomain = null; // Create public, management, control and storage networks as a part of the zone creation if (zone != null) { List ntwkOff = _networkOfferingDao.listSystemNetworkOfferings(); @@ -1369,8 +1392,11 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura } else { continue; } + + networkDomain = "cs" + Long.toHexString(Account.ACCOUNT_ID_SYSTEM) + _networkMgr.getGlobalGuestDomainSuffix(); } userNetwork.setBroadcastDomainType(broadcastDomainType); + userNetwork.setNetworkDomain(networkDomain); _networkMgr.setupNetwork(systemAccount, offering, userNetwork, plan, null, null, true, isNetworkDefault, false, null, null); } } @@ -1391,6 +1417,8 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura String type = cmd.getNetworkType(); Boolean isBasic = false; String allocationState = cmd.getAllocationState(); + String networkDomain = cmd.getDomain(); + if (allocationState == null) { allocationState = Grouping.AllocationState.Enabled.toString(); } @@ -1432,7 +1460,7 @@ public class ConfigurationManagerImpl implements ConfigurationManager, Configura } return createZone(userId, zoneName, dns1, dns2, internalDns1, internalDns2, vnetRange, guestCidr, domainVO != null ? domainVO.getName() : null, domainId, zoneType, securityGroupEnabled, - allocationState); + allocationState, networkDomain); } @Override diff --git a/server/src/com/cloud/dc/DataCenterVO.java b/server/src/com/cloud/dc/DataCenterVO.java index 950abfd619b..301f90b7f60 100644 --- a/server/src/com/cloud/dc/DataCenterVO.java +++ b/server/src/com/cloud/dc/DataCenterVO.java @@ -77,7 +77,7 @@ public class DataCenterVO implements DataCenter { private Long domainId = null; @Column(name="domain") - private String domain = null; + private String domain; @Column(name="networktype") @Enumerated(EnumType.STRING) @@ -172,13 +172,13 @@ public class DataCenterVO implements DataCenter { this.firewallProvider = firewallProvider; } - public DataCenterVO(long id, String name, String description, String dns1, String dns2, String dns3, String dns4, String vnet, String guestCidr, String domain, Long domainId, NetworkType zoneType, String zoneToken) { - this(name, description, dns1, dns2, dns3, dns4, vnet, guestCidr, domain, domainId, zoneType, false, zoneToken); + public DataCenterVO(long id, String name, String description, String dns1, String dns2, String dns3, String dns4, String vnet, String guestCidr, String domain, Long domainId, NetworkType zoneType, String zoneToken, String domainSuffix) { + this(name, description, dns1, dns2, dns3, dns4, vnet, guestCidr, domain, domainId, zoneType, false, zoneToken, domainSuffix); this.id = id; this.allocationState = Grouping.AllocationState.Enabled; } - public DataCenterVO(String name, String description, String dns1, String dns2, String dns3, String dns4, String vnet, String guestCidr, String domain, Long domainId, NetworkType zoneType, boolean securityGroupEnabled, String zoneToken) { + public DataCenterVO(String name, String description, String dns1, String dns2, String dns3, String dns4, String vnet, String guestCidr, String domain, Long domainId, NetworkType zoneType, boolean securityGroupEnabled, String zoneToken, String domainSuffix) { this.name = name; this.description = description; this.dns1 = dns1; @@ -208,7 +208,7 @@ public class DataCenterVO implements DataCenter { } this.zoneToken = zoneToken; - + this.domain = domainSuffix; } @Override diff --git a/server/src/com/cloud/domain/DomainVO.java b/server/src/com/cloud/domain/DomainVO.java index a9cbcaf2e51..59163cc4910 100644 --- a/server/src/com/cloud/domain/DomainVO.java +++ b/server/src/com/cloud/domain/DomainVO.java @@ -63,16 +63,20 @@ public class DomainVO implements Domain { @Column(name="state") private Domain.State state; + + @Column(name="network_domain") + private String networkDomain; public DomainVO() {} - public DomainVO(String name, long owner, Long parentId) { + public DomainVO(String name, long owner, Long parentId, String networkDomain) { this.parent = parentId; this.name = name; this.accountId = owner; this.path =""; this.level = 0; - this.state = Domain.State.Active; + this.state = Domain.State.Active; + this.networkDomain = networkDomain; } @Override @@ -167,6 +171,15 @@ public class DomainVO implements Domain { @Override public String toString() { return new StringBuilder("Domain:").append(id).append(path).toString(); + } + + @Override + public String getNetworkDomain() { + return networkDomain; + } + + public void setNetworkDomain(String domainSuffix) { + this.networkDomain = domainSuffix; } } diff --git a/server/src/com/cloud/domain/dao/DomainDao.java b/server/src/com/cloud/domain/dao/DomainDao.java index 0edf66cba54..6daa75a0133 100644 --- a/server/src/com/cloud/domain/dao/DomainDao.java +++ b/server/src/com/cloud/domain/dao/DomainDao.java @@ -24,7 +24,6 @@ import com.cloud.domain.DomainVO; import com.cloud.utils.db.GenericDao; public interface DomainDao extends GenericDao { - public void update(Long id, String domainName, String domainPath); public DomainVO create(DomainVO domain); public DomainVO findDomainByPath(String domainPath); public boolean isChildDomain(Long parentId, Long childId); diff --git a/server/src/com/cloud/domain/dao/DomainDaoImpl.java b/server/src/com/cloud/domain/dao/DomainDaoImpl.java index 51d2be29077..1d5dc109424 100644 --- a/server/src/com/cloud/domain/dao/DomainDaoImpl.java +++ b/server/src/com/cloud/domain/dao/DomainDaoImpl.java @@ -70,12 +70,6 @@ public class DomainDaoImpl extends GenericDaoBase implements Dom } - public void update(Long id, String domainName, String domainPath) { - DomainVO ub = createForUpdate(); - ub.setName(domainName); - ub.setPath(domainPath); - update(id, ub); - } private static String allocPath(DomainVO parentDomain, String name) { String parentPath = parentDomain.getPath(); diff --git a/server/src/com/cloud/network/NetworkManager.java b/server/src/com/cloud/network/NetworkManager.java index 2fe05fffb91..40efb393370 100644 --- a/server/src/com/cloud/network/NetworkManager.java +++ b/server/src/com/cloud/network/NetworkManager.java @@ -203,4 +203,6 @@ public interface NetworkManager extends NetworkService { IPAddressVO markIpAsUnavailable(long addrId); public String acquireGuestIpAddress(Network network, String requestedIp); + + String getGlobalGuestDomainSuffix(); } diff --git a/server/src/com/cloud/network/NetworkManagerImpl.java b/server/src/com/cloud/network/NetworkManagerImpl.java index 5600bb445e5..5a64dcba743 100755 --- a/server/src/com/cloud/network/NetworkManagerImpl.java +++ b/server/src/com/cloud/network/NetworkManagerImpl.java @@ -1685,7 +1685,22 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } } else { if (networkDomain == null) { - networkDomain = "cs" + Long.toHexString(owner.getId()) + _networkDomain; + //1) Get networkDomain from the corresponding account/domain/zone + if (isShared) { + if (domainId != null) { + networkDomain = getDomainNetworkDomain(domainId, zoneId); + } else { + networkDomain = getZoneNetworkDomain(zoneId); + } + } else { + networkDomain = getAccountNetworkDomain(owner.getId(), zoneId); + } + + //2) If null, generate networkDomain using domain suffix from the global config variables + if (networkDomain == null) { + networkDomain = "cs" + Long.toHexString(owner.getId()) + _networkDomain; + } + } else { // validate network domain if (!NetUtils.verifyDomainName(networkDomain)) { @@ -3006,4 +3021,34 @@ public class NetworkManagerImpl implements NetworkManager, NetworkService, Manag } while (result.split("\\.")[3].equals("1")); return result; } + + + protected String getZoneNetworkDomain(long zoneId) { + return _dcDao.findById(zoneId).getDomain(); + } + + protected String getDomainNetworkDomain(long domainId, long zoneId) { + String networkDomain = _domainDao.findById(domainId).getNetworkDomain(); + if (networkDomain == null) { + return getZoneNetworkDomain(zoneId); + } + + return networkDomain; + } + + protected String getAccountNetworkDomain(long accountId, long zoneId) { + String networkDomain = _accountDao.findById(accountId).getNetworkDomain(); + + if (networkDomain == null) { + //get domain level network domain + return getDomainNetworkDomain(_accountDao.findById(accountId).getDomainId(), zoneId); + } + + return networkDomain; + } + + @Override + public String getGlobalGuestDomainSuffix() { + return _networkDomain; + } } diff --git a/server/src/com/cloud/network/element/VirtualRouterElement.java b/server/src/com/cloud/network/element/VirtualRouterElement.java index dad075ece1c..3fe46b969f2 100644 --- a/server/src/com/cloud/network/element/VirtualRouterElement.java +++ b/server/src/com/cloud/network/element/VirtualRouterElement.java @@ -55,6 +55,7 @@ import com.cloud.vm.NicProfile; import com.cloud.vm.ReservationContext; import com.cloud.vm.UserVmManager; import com.cloud.vm.VirtualMachine; +import com.cloud.vm.VirtualMachine.State; import com.cloud.vm.VirtualMachineProfile; import com.cloud.vm.dao.DomainRouterDao; import com.cloud.vm.dao.UserVmDao; diff --git a/server/src/com/cloud/server/ConfigurationServerImpl.java b/server/src/com/cloud/server/ConfigurationServerImpl.java index 3d1380a046c..89ba2ed7f90 100644 --- a/server/src/com/cloud/server/ConfigurationServerImpl.java +++ b/server/src/com/cloud/server/ConfigurationServerImpl.java @@ -100,6 +100,7 @@ public class ConfigurationServerImpl implements ConfigurationServer { private final DataCenterDao _dataCenterDao; private final NetworkDao _networkDao; private final VlanDao _vlanDao; + private String _domainSuffix; public ConfigurationServerImpl() { @@ -124,6 +125,9 @@ public class ConfigurationServerImpl implements ConfigurationServer { // Get init String init = _configDao.getValue("init"); + // Get domain suffix - needed for network creation + _domainSuffix = _configDao.getValue("guest.domain.suffix"); + if (init == null || init.equals("false")) { s_logger.debug("ConfigurationServer is saving default values to the database."); @@ -856,6 +860,7 @@ public class ConfigurationServerImpl implements ConfigurationServer { long related = id; long networkOfferingId = offering.getId(); Mode mode = Mode.Static; + String networkDomain = null; BroadcastDomainType broadcastDomainType = null; TrafficType trafficType= offering.getTrafficType(); @@ -878,10 +883,12 @@ public class ConfigurationServerImpl implements ConfigurationServer { } else { continue; } + + networkDomain = "cs" + Long.toHexString(Account.ACCOUNT_ID_SYSTEM) + _domainSuffix; } if (broadcastDomainType != null) { - NetworkVO network = new NetworkVO(id, trafficType, null, mode, broadcastDomainType, networkOfferingId, zoneId, domainId, accountId, related, null, null, true, isNetworkDefault, false, null); + NetworkVO network = new NetworkVO(id, trafficType, null, mode, broadcastDomainType, networkOfferingId, zoneId, domainId, accountId, related, null, null, true, isNetworkDefault, false, networkDomain); network.setGuruName(guruNames.get(network.getTrafficType())); network.setDns1(zone.getDns1()); network.setDns2(zone.getDns2()); diff --git a/server/src/com/cloud/server/ManagementServerImpl.java b/server/src/com/cloud/server/ManagementServerImpl.java index cf681c02881..04c53d278d5 100755 --- a/server/src/com/cloud/server/ManagementServerImpl.java +++ b/server/src/com/cloud/server/ManagementServerImpl.java @@ -2922,6 +2922,7 @@ public class ManagementServerImpl implements ManagementServer { Long parentId = cmd.getParentDomainId(); Long ownerId = UserContext.current().getCaller().getId(); Account account = UserContext.current().getCaller(); + String networkDomain = cmd.getNetworkDomain(); if (ownerId == null) { ownerId = Long.valueOf(1); @@ -2939,13 +2940,21 @@ public class ManagementServerImpl implements ManagementServer { if ((account != null) && !_domainDao.isChildDomain(account.getDomainId(), parentId)) { throw new PermissionDeniedException("Unable to create domain " + name + ", permission denied."); } + + if (networkDomain != null) { + if (!NetUtils.verifyDomainName(networkDomain)) { + throw new InvalidParameterValueException( + "Invalid network domain. Total length shouldn't exceed 190 chars. Each domain label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + + "and the hyphen ('-'); can't start or end with \"-\""); + } + } SearchCriteria sc = _domainDao.createSearchCriteria(); sc.addAnd("name", SearchCriteria.Op.EQ, name); sc.addAnd("parent", SearchCriteria.Op.EQ, parentId); List domains = _domainDao.search(sc, null); if ((domains == null) || domains.isEmpty()) { - DomainVO domain = new DomainVO(name, ownerId, parentId); + DomainVO domain = new DomainVO(name, ownerId, parentId, networkDomain); try { return _domainDao.create(domain); } catch (IllegalArgumentException ex) { @@ -3065,44 +3074,66 @@ public class ManagementServerImpl implements ManagementServer { @Override @ActionEvent(eventType = EventTypes.EVENT_DOMAIN_UPDATE, eventDescription = "updating Domain") + @DB public DomainVO updateDomain(UpdateDomainCmd cmd) { Long domainId = cmd.getId(); String domainName = cmd.getDomainName(); + String networkDomain = cmd.getNetworkDomain(); // check if domain exists in the system DomainVO domain = _domainDao.findById(domainId); if (domain == null) { throw new InvalidParameterValueException("Unable to find domain " + domainId); - } else if (domain.getParent() == null) { - // check if domain is ROOT domain - and deny to edit it - throw new InvalidParameterValueException("ROOT domain can not be edited"); + } else if (domain.getParent() == null && domainName != null) { + // check if domain is ROOT domain - and deny to edit it with the new name + throw new InvalidParameterValueException("ROOT domain can not be edited with a new name"); } // check permissions - Account account = UserContext.current().getCaller(); - if ((account != null) && !isChildDomain(account.getDomainId(), domain.getId())) { - throw new PermissionDeniedException("Unable to update domain " + domainId + ", permission denied"); + Account caller = UserContext.current().getCaller(); + _accountMgr.checkAccess(caller, domain); + + //domain name is unique in the cloud + if (domainName != null) { + SearchCriteria sc = _domainDao.createSearchCriteria(); + sc.addAnd("name", SearchCriteria.Op.EQ, domainName); + List domains = _domainDao.search(sc, null); + + if (!domains.isEmpty()) { + throw new InvalidParameterValueException("Failed to update domain id=" + domainId + "; domain with name " + domainName + " already exists in the system"); + } } - if (domainName == null || domainName.equals(domain.getName())) { - return _domainDao.findById(domainId); + //validate network domain + if (networkDomain != null){ + if (!NetUtils.verifyDomainName(networkDomain)) { + throw new InvalidParameterValueException( + "Invalid network domain. Total length shouldn't exceed 190 chars. Each domain label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + + "and the hyphen ('-'); can't start or end with \"-\""); + } } - SearchCriteria sc = _domainDao.createSearchCriteria(); - sc.addAnd("name", SearchCriteria.Op.EQ, domainName); - List domains = _domainDao.search(sc, null); - if ((domains == null) || domains.isEmpty()) { - // whilst updating a domain name, update its path and update all its children's path - domain = _domainDao.findById(domainId); + Transaction txn = Transaction.currentTxn(); + + txn.start(); + + if (domainName != null) { String updatedDomainPath = getUpdatedDomainPath(domain.getPath(), domainName); updateDomainChildren(domain, updatedDomainPath); - _domainDao.update(domainId, domainName, updatedDomainPath); - return _domainDao.findById(domainId); - } else { - domain = _domainDao.findById(domainId); - s_logger.error("Domain with name " + domainName + " already exists in the system"); - throw new CloudRuntimeException("Failed to update domain " + domainId); + domain.setName(domainName); + domain.setPath(updatedDomainPath); } + + if (networkDomain != null) { + domain.setNetworkDomain(networkDomain); + } + + _domainDao.update(domainId, domain); + + txn.commit(); + + return _domainDao.findById(domainId); + } private String getUpdatedDomainPath(String oldPath, String newName) { diff --git a/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java b/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java index b52964505ed..56e53ae3eed 100644 --- a/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java +++ b/server/src/com/cloud/upgrade/DatabaseUpgradeChecker.java @@ -44,6 +44,7 @@ import com.cloud.upgrade.dao.Upgrade222to224; import com.cloud.upgrade.dao.Upgrade224to225; import com.cloud.upgrade.dao.Upgrade225to226; import com.cloud.upgrade.dao.Upgrade227to228; +import com.cloud.upgrade.dao.Upgrade228to229; import com.cloud.upgrade.dao.UpgradeSnapshot217to224; import com.cloud.upgrade.dao.UpgradeSnapshot223to224; import com.cloud.upgrade.dao.VersionDao; @@ -66,16 +67,17 @@ public class DatabaseUpgradeChecker implements SystemIntegrityChecker { public DatabaseUpgradeChecker() { _dao = ComponentLocator.inject(VersionDaoImpl.class); - _upgradeMap.put("2.1.7", new DbUpgrade[] { new Upgrade217to218(), new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228() }); - _upgradeMap.put("2.1.8", new DbUpgrade[] { new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228() }); - _upgradeMap.put("2.1.9", new DbUpgrade[] { new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228() }); - _upgradeMap.put("2.2.1", new DbUpgrade[] { new Upgrade221to222(), new UpgradeSnapshot223to224(), new Upgrade222to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228()}); - _upgradeMap.put("2.2.2", new DbUpgrade[] { new Upgrade222to224(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228() }); - _upgradeMap.put("2.2.3", new DbUpgrade[] { new Upgrade222to224(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228() }); - _upgradeMap.put("2.2.4", new DbUpgrade[] { new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228() }); + _upgradeMap.put("2.1.7", new DbUpgrade[] { new Upgrade217to218(), new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229()}); + _upgradeMap.put("2.1.8", new DbUpgrade[] { new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229()}); + _upgradeMap.put("2.1.9", new DbUpgrade[] { new Upgrade218to22(), new Upgrade221to222(), new UpgradeSnapshot217to224(), new Upgrade222to224(), new Upgrade218to224DomainVlans(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229()}); + _upgradeMap.put("2.2.1", new DbUpgrade[] { new Upgrade221to222(), new UpgradeSnapshot223to224(), new Upgrade222to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229()}); + _upgradeMap.put("2.2.2", new DbUpgrade[] { new Upgrade222to224(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229()}); + _upgradeMap.put("2.2.3", new DbUpgrade[] { new Upgrade222to224(), new UpgradeSnapshot223to224(), new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229()}); + _upgradeMap.put("2.2.4", new DbUpgrade[] { new Upgrade224to225(), new Upgrade225to226(), new Upgrade227to228(), new Upgrade228to229()}); _upgradeMap.put("2.2.5", new DbUpgrade[] { new Upgrade225to226(), new Upgrade227to228() }); - _upgradeMap.put("2.2.6", new DbUpgrade[] { new Upgrade227to228()}); - _upgradeMap.put("2.2.7", new DbUpgrade[] { new Upgrade227to228()}); + _upgradeMap.put("2.2.6", new DbUpgrade[] { new Upgrade227to228(), new Upgrade228to229()}); + _upgradeMap.put("2.2.7", new DbUpgrade[] { new Upgrade227to228(), new Upgrade228to229()}); + _upgradeMap.put("2.2.8", new DbUpgrade[] { new Upgrade228to229()}); } protected void runScript(Connection conn, File file) { diff --git a/server/src/com/cloud/upgrade/dao/Upgrade228to229.java b/server/src/com/cloud/upgrade/dao/Upgrade228to229.java new file mode 100644 index 00000000000..f626c8c6f07 --- /dev/null +++ b/server/src/com/cloud/upgrade/dao/Upgrade228to229.java @@ -0,0 +1,65 @@ +/** + * Copyright (C) 2010 Cloud.com, Inc. All rights reserved. + * + * This software is licensed under the GNU General Public License v3 or later. + * + * It 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 3 of the License, or any later version. + * This program 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 this program. If not, see . + * + */ +package com.cloud.upgrade.dao; + +import java.io.File; +import java.sql.Connection; + +import org.apache.log4j.Logger; + +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.script.Script; + +public class Upgrade228to229 implements DbUpgrade { + final static Logger s_logger = Logger.getLogger(Upgrade228to229.class); + + @Override + public String[] getUpgradableVersionRange() { + return new String[] { "2.2.8", "2.2.8"}; + } + + @Override + public String getUpgradedVersion() { + return "2.2.9"; + } + + @Override + public boolean supportsRollingUpgrade() { + return true; + } + + @Override + public File[] getPrepareScripts() { + String script = Script.findScript("", "db/schema-228to229.sql"); + if (script == null) { + throw new CloudRuntimeException("Unable to find db/schema-228to229.sql"); + } + + return new File[] { new File(script) }; + } + + @Override + public void performDataMigration(Connection conn) { + } + + @Override + public File[] getCleanupScripts() { + return null; + } + +} diff --git a/server/src/com/cloud/user/AccountManagerImpl.java b/server/src/com/cloud/user/AccountManagerImpl.java index 7dc33f047af..2deeda382d6 100755 --- a/server/src/com/cloud/user/AccountManagerImpl.java +++ b/server/src/com/cloud/user/AccountManagerImpl.java @@ -107,6 +107,7 @@ import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.Transaction; import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.utils.net.NetUtils; import com.cloud.vm.InstanceGroupVO; import com.cloud.vm.ReservationContext; import com.cloud.vm.ReservationContextImpl; @@ -1205,6 +1206,8 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag short userType = cmd.getAccountType().shortValue(); DomainVO domain = _domainDao.findById(domainId); checkAccess(UserContext.current().getCaller(), domain); + String networkDomain = cmd.getNetworkDomain(); + try { if (accountName == null) { accountName = username; @@ -1229,6 +1232,14 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag if (!_userAccountDao.validateUsernameInDomain(username, domainId)) { throw new CloudRuntimeException("The user " + username + " already exists in domain " + domainId); } + + if (networkDomain != null) { + if (!NetUtils.verifyDomainName(networkDomain)) { + throw new InvalidParameterValueException( + "Invalid network domain. Total length shouldn't exceed 190 chars. Each domain label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + + "and the hyphen ('-'); can't start or end with \"-\""); + } + } if (accountId == null) { if ((userType < Account.ACCOUNT_TYPE_NORMAL) || (userType > Account.ACCOUNT_TYPE_READ_ONLY_ADMIN)) { @@ -1250,6 +1261,7 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag newAccount.setDomainId(domainId); newAccount.setType(userType); newAccount.setState(State.enabled); + newAccount.setNetworkDomain(networkDomain); newAccount = _accountDao.persist(newAccount); accountId = newAccount.getId(); } @@ -1690,6 +1702,7 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag Long domainId = cmd.getDomainId(); String accountName = cmd.getAccountName(); String newAccountName = cmd.getNewName(); + String networkDomain = cmd.getNetworkDomain(); boolean success = false; Account account = _accountDao.findAccount(accountName, domainId); @@ -1719,17 +1732,27 @@ public class AccountManagerImpl implements AccountManager, AccountService, Manag // to // update // itself - throw new PermissionDeniedException("There already exists an account with the name:" + newAccountName + " in the domain:" + domainId + " with existing account id:" + throw new InvalidParameterValueException("There already exists an account with the name:" + newAccountName + " in the domain:" + domainId + " with existing account id:" + duplicateAcccount.getId()); } - if (account.getAccountName().equals(newAccountName)) { - success = true; - } else { - AccountVO acctForUpdate = _accountDao.createForUpdate(); - acctForUpdate.setAccountName(newAccountName); - success = _accountDao.update(Long.valueOf(account.getId()), acctForUpdate); + if (networkDomain != null) { + if (!NetUtils.verifyDomainName(networkDomain)) { + throw new InvalidParameterValueException( + "Invalid network domain. Total length shouldn't exceed 190 chars. Each domain label must be between 1 and 63 characters long, can contain ASCII letters 'a' through 'z', the digits '0' through '9', " + + "and the hyphen ('-'); can't start or end with \"-\""); + } } + + AccountVO acctForUpdate = _accountDao.findById(account.getId()); + acctForUpdate.setAccountName(newAccountName); + + if (networkDomain != null) { + acctForUpdate.setNetworkDomain(networkDomain); + } + + success = _accountDao.update(account.getId(), acctForUpdate); + if (success) { return _accountDao.findById(account.getId()); } else { diff --git a/server/test/com/cloud/async/TestAsyncJobManager.java b/server/test/com/cloud/async/TestAsyncJobManager.java index 7cd74550fe2..1e259341d21 100644 --- a/server/test/com/cloud/async/TestAsyncJobManager.java +++ b/server/test/com/cloud/async/TestAsyncJobManager.java @@ -234,25 +234,25 @@ public class TestAsyncJobManager extends ComponentTestCase { getRandomMilliseconds(1, 100); DomainDao domainDao = new DomainDaoImpl(); - DomainVO domain1 = new DomainVO("d1", 2L, 1L); + DomainVO domain1 = new DomainVO("d1", 2L, 1L, null); domainDao.create(domain1); - DomainVO domain2 = new DomainVO("d2", 2L, 1L); + DomainVO domain2 = new DomainVO("d2", 2L, 1L, null); domainDao.create(domain2); - DomainVO domain3 = new DomainVO("d3", 2L, 1L); + DomainVO domain3 = new DomainVO("d3", 2L, 1L, null); domainDao.create(domain3); - DomainVO domain11 = new DomainVO("d11", 2L, domain1.getId()); + DomainVO domain11 = new DomainVO("d11", 2L, domain1.getId(), null); domainDao.create(domain11); domainDao.remove(domain11.getId()); - DomainVO domain12 = new DomainVO("d12", 2L, domain1.getId()); + DomainVO domain12 = new DomainVO("d12", 2L, domain1.getId(), null); domainDao.create(domain12); domainDao.remove(domain3.getId()); - DomainVO domain4 = new DomainVO("d4", 2L, 1L); + DomainVO domain4 = new DomainVO("d4", 2L, 1L, null); domainDao.create(domain4); } } diff --git a/setup/db/create-schema.sql b/setup/db/create-schema.sql index de8132e4212..c887d9b1b1a 100755 --- a/setup/db/create-schema.sql +++ b/setup/db/create-schema.sql @@ -991,6 +991,7 @@ CREATE TABLE `cloud`.`domain` ( `next_child_seq` bigint unsigned NOT NULL DEFAULT 1, `removed` datetime COMMENT 'date removed', `state` char(32) NOT NULL default 'Active' COMMENT 'state of the domain', + `network_domain` varchar(255), PRIMARY KEY (`id`), UNIQUE (parent, name, removed), INDEX `i_domain__path`(`path`) @@ -1004,6 +1005,7 @@ CREATE TABLE `cloud`.`account` ( `state` varchar(10) NOT NULL default 'enabled', `removed` datetime COMMENT 'date removed', `cleanup_needed` tinyint(1) NOT NULL default '0', + `network_domain` varchar(255), PRIMARY KEY (`id`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; diff --git a/setup/db/db/schema-228to229.sql b/setup/db/db/schema-228to229.sql new file mode 100644 index 00000000000..4ad8b1e35b0 --- /dev/null +++ b/setup/db/db/schema-228to229.sql @@ -0,0 +1,7 @@ +--; +-- Schema upgrade from 2.2.8 to 2.2.9; +--; + +ALTER TABLE `cloud`.`account` ADD COLUMN `network_domain` varchar(255); +ALTER TABLE `cloud`.`domain` ADD COLUMN `network_domain` varchar(255); +