Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions api/src/main/java/com/cloud/event/EventTypes.java
Original file line number Diff line number Diff line change
Expand Up @@ -318,6 +318,7 @@ public class EventTypes {
public static final String EVENT_DOMAIN_CREATE = "DOMAIN.CREATE";
public static final String EVENT_DOMAIN_DELETE = "DOMAIN.DELETE";
public static final String EVENT_DOMAIN_UPDATE = "DOMAIN.UPDATE";
public static final String EVENT_DOMAIN_MOVE = "DOMAIN.MOVE";

// Snapshots
public static final String EVENT_SNAPSHOT_CREATE = "SNAPSHOT.CREATE";
Expand Down Expand Up @@ -858,6 +859,7 @@ public class EventTypes {
entityEventDetails.put(EVENT_DOMAIN_CREATE, Domain.class);
entityEventDetails.put(EVENT_DOMAIN_DELETE, Domain.class);
entityEventDetails.put(EVENT_DOMAIN_UPDATE, Domain.class);
entityEventDetails.put(EVENT_DOMAIN_MOVE, Domain.class);

// Snapshots
entityEventDetails.put(EVENT_SNAPSHOT_CREATE, Snapshot.class);
Expand Down
3 changes: 3 additions & 0 deletions api/src/main/java/com/cloud/user/DomainService.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,9 +20,11 @@

import org.apache.cloudstack.api.command.admin.domain.ListDomainChildrenCmd;
import org.apache.cloudstack.api.command.admin.domain.ListDomainsCmd;
import org.apache.cloudstack.api.command.admin.domain.MoveDomainCmd;

import com.cloud.domain.Domain;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.utils.Pair;

public interface DomainService {
Expand Down Expand Up @@ -66,4 +68,5 @@ public interface DomainService {
*/
Domain findDomainByIdOrPath(Long id, String domainPath);

Domain moveDomainAndChildrenToNewParentDomain(MoveDomainCmd cmd) throws ResourceAllocationException;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command.admin.domain;

import com.cloud.domain.Domain;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.user.Account;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.DomainResponse;

@APICommand(name = "moveDomain", description = "Moves a domain and its children to a new parent domain.", since = "4.19.0.0", responseObject = DomainResponse.class,
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = {RoleType.Admin})
public class MoveDomainCmd extends BaseCmd {

private static final String APINAME = "moveDomain";
@Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, required = true, entityType = DomainResponse.class, description = "The ID of the domain to be moved.")
private Long domainId;

@Parameter(name = ApiConstants.PARENT_DOMAIN_ID, type = CommandType.UUID, required = true, entityType = DomainResponse.class,
description = "The ID of the new parent domain of the domain to be moved.")
private Long parentDomainId;

public Long getDomainId() {
return domainId;
}

public Long getParentDomainId() {
Comment thread
JoaoJandre marked this conversation as resolved.
return parentDomainId;
}

@Override
public String getCommandName() {
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
}

@Override
public long getEntityOwnerId() {
return Account.ACCOUNT_ID_SYSTEM;
}

@Override
public void execute() throws ResourceAllocationException {
Domain domain = _domainService.moveDomainAndChildrenToNewParentDomain(this);

if (domain != null) {
DomainResponse response = _responseGenerator.createDomainResponse(domain);
response.setResponseName(getCommandName());
this.setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to move the domain.");
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package com.cloud.network.dao;

import java.util.List;
import java.util.Map;

import com.cloud.utils.db.GenericDao;

Expand All @@ -26,4 +27,6 @@ public interface NetworkDomainDao extends GenericDao<NetworkDomainVO, Long> {
NetworkDomainVO getDomainNetworkMapByNetworkId(long networkId);

List<Long> listNetworkIdsByDomain(long domainId);

Map<Long, List<String>> listDomainsOfSharedNetworksUsedByDomainPath(String domainPath);
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,17 @@
// under the License.
package com.cloud.network.dao;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;


import com.cloud.utils.db.TransactionLegacy;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import com.cloud.utils.db.DB;
Expand All @@ -31,9 +38,23 @@
@Component
@DB()
public class NetworkDomainDaoImpl extends GenericDaoBase<NetworkDomainVO, Long> implements NetworkDomainDao {
public static Logger logger = Logger.getLogger(NetworkDomainDaoImpl.class.getName());
final SearchBuilder<NetworkDomainVO> AllFieldsSearch;
final SearchBuilder<NetworkDomainVO> DomainsSearch;

private static final String LIST_DOMAINS_OF_SHARED_NETWORKS_USED_BY_DOMAIN_PATH = "SELECT shared_nw.domain_id, \n" +
"GROUP_CONCAT('VM:', vm.uuid, ' | NW:' , network.uuid) \n" +
"FROM cloud.domain_network_ref AS shared_nw\n" +
"INNER JOIN cloud.nics AS nic ON (nic.network_id = shared_nw.network_id AND nic.removed IS NULL)\n" +
"INNER JOIN cloud.vm_instance AS vm ON (vm.id = nic.instance_id)\n" +
"INNER JOIN cloud.domain AS domain ON (domain.id = vm.domain_id)\n" +
"INNER JOIN cloud.domain AS domain_sn ON (domain_sn.id = shared_nw.domain_id)\n" +
"INNER JOIN cloud.networks AS network ON (shared_nw.network_id = network.id)\n" +
"WHERE shared_nw.subdomain_access = 1\n" +
"AND domain.path LIKE ?\n" +
"AND domain_sn.path NOT LIKE ?\n" +
"GROUP BY shared_nw.network_id";

protected NetworkDomainDaoImpl() {
super();

Expand Down Expand Up @@ -71,4 +92,37 @@ public List<Long> listNetworkIdsByDomain(long domainId) {
}
return networkIdsToReturn;
}

@Override
public Map<Long, List<String>> listDomainsOfSharedNetworksUsedByDomainPath(String domainPath) {
logger.debug(String.format("Retrieving the domains of the shared networks with subdomain access used by domain with path [%s].", domainPath));

TransactionLegacy txn = TransactionLegacy.currentTxn();
try (PreparedStatement pstmt = txn.prepareStatement(LIST_DOMAINS_OF_SHARED_NETWORKS_USED_BY_DOMAIN_PATH)) {
Map<Long, List<String>> domainsOfSharedNetworksUsedByDomainPath = new HashMap<>();

String domainSearch = domainPath.concat("%");
pstmt.setString(1, domainSearch);
pstmt.setString(2, domainSearch);

try (ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
Long domainId = rs.getLong(1);
List<String> vmUuidsAndNetworkUuids = Arrays.asList(rs.getString(2).split(","));

domainsOfSharedNetworksUsedByDomainPath.put(domainId, vmUuidsAndNetworkUuids);
}
}

return domainsOfSharedNetworksUsedByDomainPath;
} catch (SQLException e) {
logger.error(String.format("Failed to retrieve the domains of the shared networks with subdomain access used by domain with path [%s] due to [%s]. Returning an empty "
+ "list of domains.", domainPath, e.getMessage()));

logger.debug(String.format("Failed to retrieve the domains of the shared networks with subdomain access used by domain with path [%s]. Returning an empty "
+ "list of domains.", domainPath), e);

return new HashMap<>();
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
package org.apache.cloudstack.affinity.dao;

import java.util.List;
import java.util.Map;

import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO;

Expand All @@ -28,4 +29,6 @@ public interface AffinityGroupDomainMapDao extends GenericDao<AffinityGroupDomai

List<AffinityGroupDomainMapVO> listByDomain(Object... domainId);

Map<Long, List<String>> listDomainsOfAffinityGroupsUsedByDomainPath(String domainPath);

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,23 +16,46 @@
// under the License.
package org.apache.cloudstack.affinity.dao;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.annotation.PostConstruct;

import org.apache.cloudstack.affinity.AffinityGroupDomainMapVO;
import org.apache.log4j.Logger;

import com.cloud.network.dao.NetworkDomainDaoImpl;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
import com.cloud.utils.db.SearchCriteria.Op;
import com.cloud.utils.db.TransactionLegacy;

public class AffinityGroupDomainMapDaoImpl extends GenericDaoBase<AffinityGroupDomainMapVO, Long> implements AffinityGroupDomainMapDao {
public static Logger logger = Logger.getLogger(NetworkDomainDaoImpl.class.getName());

private SearchBuilder<AffinityGroupDomainMapVO> ListByAffinityGroup;

private SearchBuilder<AffinityGroupDomainMapVO> DomainsSearch;

private static final String LIST_DOMAINS_WITH_AFFINITY_GROUPS_WITH_SUBDOMAIN_ACCESS_USED_BY_DOMAIN_PATH = "SELECT affinity_group_domain_map.domain_id, \n" +
"GROUP_CONCAT('VM:', vm.uuid, ' | AG:' , affinity_group.uuid) \n" +
"FROM cloud.affinity_group_domain_map AS affinity_group_domain_map\n" +
"INNER JOIN cloud.affinity_group_vm_map AS affinity_group_vm_map ON (cloud.affinity_group_domain_map.affinity_group_id = affinity_group_vm_map.affinity_group_id)\n" +
"INNER JOIN cloud.vm_instance AS vm ON (vm.id = affinity_group_vm_map.instance_id)\n" +
"INNER JOIN cloud.domain AS domain ON (domain.id = vm.domain_id)\n" +
"INNER JOIN cloud.domain AS domain_sn ON (domain_sn.id = affinity_group_domain_map.domain_id)\n" +
"INNER JOIN cloud.affinity_group AS affinity_group ON (affinity_group.id = affinity_group_domain_map.affinity_group_id)\n" +
"WHERE affinity_group_domain_map.subdomain_access = 1\n" +
"AND domain.path LIKE ?\n" +
"AND domain_sn.path NOT LIKE ?\n" +
"GROUP BY affinity_group.id";

public AffinityGroupDomainMapDaoImpl() {
}

Expand Down Expand Up @@ -62,4 +85,38 @@ public List<AffinityGroupDomainMapVO> listByDomain(Object... domainId) {
return listBy(sc);
}

@Override
public Map<Long, List<String>> listDomainsOfAffinityGroupsUsedByDomainPath(String domainPath) {
logger.debug(String.format("Retrieving the domains of the affinity groups with subdomain access used by domain with path [%s].", domainPath));

TransactionLegacy txn = TransactionLegacy.currentTxn();
try (PreparedStatement pstmt = txn.prepareStatement(LIST_DOMAINS_WITH_AFFINITY_GROUPS_WITH_SUBDOMAIN_ACCESS_USED_BY_DOMAIN_PATH)) {
Map<Long, List<String>> domainsOfAffinityGroupsUsedByDomainPath = new HashMap<>();

String domainSearch = domainPath.concat("%");
pstmt.setString(1, domainSearch);
pstmt.setString(2, domainSearch);


try (ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
Long domainId = rs.getLong(1);
List<String> vmUuidsAndAffinityGroupUuids = Arrays.asList(rs.getString(2).split(","));

domainsOfAffinityGroupsUsedByDomainPath.put(domainId, vmUuidsAndAffinityGroupUuids);
}
}

return domainsOfAffinityGroupsUsedByDomainPath;
} catch (SQLException e) {
logger.error(String.format("Failed to retrieve the domains of the affinity groups with subdomain access used by domain with path [%s] due to [%s]. Returning an " +
"empty list of domains.", domainPath, e.getMessage()));

logger.debug(String.format("Failed to retrieve the domains of the affinity groups with subdomain access used by domain with path [%s]. Returning an empty "
+ "list of domains.", domainPath), e);

return new HashMap<>();
}
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
package com.cloud.api.query.dao;

import java.util.List;
import java.util.Map;

import org.apache.cloudstack.api.response.NetworkOfferingResponse;

Expand Down Expand Up @@ -52,4 +53,6 @@ public interface NetworkOfferingJoinDao extends GenericDao<NetworkOfferingJoinVO
NetworkOfferingResponse newNetworkOfferingResponse(NetworkOffering nof);

NetworkOfferingJoinVO newNetworkOfferingView(NetworkOffering nof);

Map<Long, List<String>> listDomainsOfNetworkOfferingsUsedByDomainPath(String domainPath);
}
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,15 @@

package com.cloud.api.query.dao;

import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.cloud.utils.db.TransactionLegacy;
import org.apache.commons.lang3.StringUtils;
import org.apache.cloudstack.api.response.NetworkOfferingResponse;
import org.apache.log4j.Logger;
Expand All @@ -44,6 +51,17 @@ protected NetworkOfferingJoinDaoImpl() {
_count = "select count(distinct id) from network_offering_view WHERE ";
}

private static final String LIST_DOMAINS_OF_NETWORK_OFFERINGS_USED_BY_DOMAIN_PATH = "SELECT nov.domain_id, \n" +
" GROUP_CONCAT('Network:', net.uuid) \n" +
" FROM cloud.network_offering_view AS nov\n" +
" INNER JOIN cloud.networks AS net ON (net.network_offering_id = nov.id) \n" +
" INNER JOIN cloud.domain AS domain ON (domain.id = net.domain_id) \n" +
" INNER JOIN cloud.domain AS domain_so ON (domain_so.id = nov.domain_id) \n" +
" WHERE domain.path LIKE ? \n" +
" AND domain_so.path NOT LIKE ? \n" +
" AND net.removed IS NULL \n" +
" GROUP BY nov.id";

@Override
public List<NetworkOfferingJoinVO> findByDomainId(long domainId, Boolean includeAllDomainOffering) {
SearchBuilder<NetworkOfferingJoinVO> sb = createSearchBuilder();
Expand Down Expand Up @@ -120,4 +138,39 @@ public NetworkOfferingJoinVO newNetworkOfferingView(NetworkOffering offering) {
assert offerings != null && offerings.size() == 1 : "No network offering found for offering id " + offering.getId();
return offerings.get(0);
}



@Override
public Map<Long, List<String>> listDomainsOfNetworkOfferingsUsedByDomainPath(String domainPath) {
s_logger.debug(String.format("Retrieving the domains of the network offerings used by domain with path [%s].", domainPath));

TransactionLegacy txn = TransactionLegacy.currentTxn();
try (PreparedStatement pstmt = txn.prepareStatement(LIST_DOMAINS_OF_NETWORK_OFFERINGS_USED_BY_DOMAIN_PATH)) {
Map<Long, List<String>> domainsOfNetworkOfferingsUsedByDomainPath = new HashMap<>();

String domainSearch = domainPath.concat("%");
pstmt.setString(1, domainSearch);
pstmt.setString(2, domainSearch);

try (ResultSet rs = pstmt.executeQuery()) {
while (rs.next()) {
Long domainId = rs.getLong(1);
List<String> networkUuids = Arrays.asList(rs.getString(2).split(","));

domainsOfNetworkOfferingsUsedByDomainPath.put(domainId, networkUuids);
}
}

return domainsOfNetworkOfferingsUsedByDomainPath;
} catch (SQLException e) {
s_logger.error(String.format("Failed to retrieve the domains of the network offerings used by domain with path [%s] due to [%s]. Returning an empty "
+ "list of domains.", domainPath, e.getMessage()));

s_logger.debug(String.format("Failed to retrieve the domains of the network offerings used by domain with path [%s]. Returning an empty " +
"list of domains.", domainPath), e);

return new HashMap<>();
}
}
}
Loading