Changes done to AddDnsServer, ListDnsServer, DeleteDnsServer and UpdateDnsServer

This commit is contained in:
Manoj Kumar 2026-02-12 19:27:32 +05:30
parent 6ef7f9bcd4
commit 9911c280e1
No known key found for this signature in database
GPG Key ID: E952B7234D2C6F88
16 changed files with 637 additions and 50 deletions

View File

@ -1333,6 +1333,11 @@ public class ApiConstants {
public static final String OBJECT_STORAGE_LIMIT = "objectstoragelimit";
public static final String OBJECT_STORAGE_TOTAL = "objectstoragetotal";
// DNS provider related
public static final String NAME_SERVERS = "nameservers";
public static final String CREDENTIALS = "credentials";
public static final String PUBLIC_DOMAIN_SUFFIX = "publicdomainsuffix";
public static final String PARAMETER_DESCRIPTION_ACTIVATION_RULE = "Quota tariff's activation rule. It can receive a JS script that results in either " +
"a boolean or a numeric value: if it results in a boolean value, the tariff value will be applied according to the result; if it results in a numeric value, the " +
"numeric value will be applied; if the result is neither a boolean nor a numeric value, the tariff will not be applied. If the rule is not informed, the tariff " +

View File

@ -21,12 +21,15 @@ import javax.inject.Inject;
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.DnsServerResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.dns.DnsProviderManager;
import org.apache.cloudstack.dns.DnsServer;
import org.apache.commons.lang3.BooleanUtils;
@APICommand(name = "addDnsServer", description = "Adds a new external DNS server",
responseObject = DnsServerResponse.class, requestHasSensitiveInfo = true)
@ -45,14 +48,23 @@ public class AddDnsServerCmd extends BaseCmd {
@Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, description = "API URL of the provider")
private String url;
@Parameter(name = "provider", type = CommandType.STRING, required = true, description = "Provider type (e.g., PowerDNS)")
@Parameter(name = ApiConstants.PROVIDER, type = CommandType.STRING, required = true, description = "Provider type (e.g., PowerDNS)")
private String provider;
@Parameter(name = ApiConstants.USERNAME, type = CommandType.STRING, description = "API Username")
private String username;
@Parameter(name = ApiConstants.CREDENTIALS, type = CommandType.STRING, required = false, description = "API Key or Credentials for the external provider")
private String credentials;
@Parameter(name = ApiConstants.PASSWORD, type = CommandType.STRING, description = "API Password or Token")
private String password;
@Parameter(name = ApiConstants.PORT, type = CommandType.INTEGER, description = "Port number of the external DNS server")
private Integer port;
@Parameter(name = ApiConstants.IS_PUBLIC, type = CommandType.BOOLEAN, description = "Whether the DNS server is publicly accessible by other accounts")
private Boolean isPublic;
@Parameter(name = ApiConstants.PUBLIC_DOMAIN_SUFFIX, type = CommandType.STRING, description = "The domain suffix used for public access (e.g. public.example.com)")
private String publicDomainSuffix;
@Parameter(name = ApiConstants.NAME_SERVERS, type = CommandType.STRING, description = "Comma separated list of name servers")
private String nameServers;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
@ -61,19 +73,45 @@ public class AddDnsServerCmd extends BaseCmd {
public String getName() { return name; }
public String getUrl() { return url; }
public String getProvider() { return provider; }
public String getUsername() { return username; }
public String getPassword() { return password; }
public String getCredentials() {
return credentials;
}
@Override
public void execute() {
DnsServer server = dnsProviderManager.addDnsServer(this);
DnsServerResponse response = dnsProviderManager.createDnsServerResponse(server);
response.setResponseName(getCommandName());
setResponseObject(response);
public Integer getPort() {
return port;
}
public Boolean isPublic() {
return BooleanUtils.isTrue(isPublic);
}
public String getPublicDomainSuffix() {
return publicDomainSuffix;
}
public String getNameServers() {
return nameServers;
}
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
@Override
public void execute() {
try {
DnsServer server = dnsProviderManager.addDnsServer(this);
if (server != null) {
DnsServerResponse response = dnsProviderManager.createDnsServerResponse(server);
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add DNS server");
}
} catch (Exception ex) {
logger.error("Failed to add DNS server", ex);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
}
}
}

View File

@ -76,5 +76,5 @@ public class DeleteDnsServerCmd extends BaseAsyncCmd {
public String getEventType() { return EventTypes.EVENT_DNS_SERVER_DELETE; }
@Override
public String getEventDescription() { return "Deleting DNS Server ID: " + getId(); }
public String getEventDescription() { return "Deleting DNS server ID: " + getId(); }
}

View File

@ -51,6 +51,7 @@ public class ListDnsServersCmd extends BaseListAccountResourcesCmd {
public void execute() {
ListResponse<DnsServerResponse> response = dnsProviderManager.listDnsServers(this);
response.setResponseName(getCommandName());
response.setObjectName("dnsserver");
setResponseObject(response);
}

View File

@ -0,0 +1,112 @@
// 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.user.dns;
import javax.inject.Inject;
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.DnsServerResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.dns.DnsProviderManager;
import org.apache.cloudstack.dns.DnsServer;
import org.apache.commons.lang3.BooleanUtils;
@APICommand(name = "updateDnsServer", description = "Update DNS server",
responseObject = DnsServerResponse.class, requestHasSensitiveInfo = true)
public class UpdateDnsServerCmd extends BaseCmd {
@Inject
DnsProviderManager dnsProviderManager;
/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = DnsServerResponse.class,
required = true, description = "The ID of the DNS server to update")
private Long id;
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "Name of the DNS server")
private String name;
@Parameter(name = ApiConstants.URL, type = CommandType.STRING, description = "API URL of the provider")
private String url;
@Parameter(name = ApiConstants.CREDENTIALS, type = CommandType.STRING, required = false, description = "API Key or Credentials for the external provider")
private String credentials;
@Parameter(name = ApiConstants.PORT, type = CommandType.INTEGER, description = "Port number of the external DNS server")
private Integer port;
@Parameter(name = ApiConstants.IS_PUBLIC, type = CommandType.BOOLEAN, description = "Whether the DNS server is publicly accessible by other accounts")
private Boolean isPublic;
@Parameter(name = ApiConstants.PUBLIC_DOMAIN_SUFFIX, type = CommandType.STRING, description = "The domain suffix used for public access (e.g. public.example.com)")
private String publicDomainSuffix;
@Parameter(name = ApiConstants.NAME_SERVERS, type = CommandType.STRING, description = "Comma separated list of name servers")
private String nameServers;
/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
public Long getId() { return id; }
public String getName() { return name; }
public String getUrl() { return url; }
public String getCredentials() {
return credentials;
}
public Integer getPort() {
return port;
}
public Boolean isPublic() {
return BooleanUtils.isTrue(isPublic);
}
public String getPublicDomainSuffix() {
return publicDomainSuffix;
}
public String getNameServers() { return nameServers; }
@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}
@Override
public void execute() {
try {
DnsServer server = dnsProviderManager.updateDnsServer(this);
if (server != null) {
DnsServerResponse response = dnsProviderManager.createDnsServerResponse(server);
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update DNS server");
}
} catch (Exception ex) {
logger.error("Failed to add update server", ex);
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
}
}
}

View File

@ -17,9 +17,12 @@
package org.apache.cloudstack.api.response;
import java.util.List;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;
import org.apache.cloudstack.api.EntityReference;
import org.apache.cloudstack.dns.DnsProviderType;
import org.apache.cloudstack.dns.DnsServer;
import com.cloud.serializer.Param;
@ -29,39 +32,69 @@ import com.google.gson.annotations.SerializedName;
public class DnsServerResponse extends BaseResponse {
@SerializedName(ApiConstants.ID)
@Param(description = "the ID of the DNS server")
@Param(description = "ID of the DNS server")
private String id;
@SerializedName(ApiConstants.NAME)
@Param(description = "the name of the DNS server")
@Param(description = "Name of the DNS server")
private String name;
@SerializedName(ApiConstants.URL)
@Param(description = "the URL of the DNS server API")
@Param(description = "URL of the DNS server API")
private String url;
@SerializedName(ApiConstants.PORT)
@Param(description = "The port of the DNS server")
private Integer port;
@SerializedName(ApiConstants.PROVIDER)
@Param(description = "the provider type of the DNS server")
private String provider;
@Param(description = "The provider type of the DNS server")
private DnsProviderType provider;
@SerializedName(ApiConstants.ACCOUNT)
@Param(description = "the account associated with the DNS server")
private String accountName;
@SerializedName(ApiConstants.IS_PUBLIC)
@Param(description = "Is the DNS server publicly available")
private Boolean isPublic;
@SerializedName(ApiConstants.PROJECT)
@Param(description = "the project name of the DNS server")
private String projectName;
@SerializedName(ApiConstants.PUBLIC_DOMAIN_SUFFIX) @Param(description = "The public domain suffix for the DNS server")
private String publicDomainSuffix;
@SerializedName(ApiConstants.DOMAIN_ID)
@Param(description = "the domain ID of the DNS server")
private String domainId;
@SerializedName(ApiConstants.DOMAIN)
@Param(description = "the domain name of the DNS server")
private String domainName;
@SerializedName(ApiConstants.NAME_SERVERS) @Param(description = "Name servers entries associated to DNS server")
private List<String> nameServers;
public DnsServerResponse() {
super();
setObjectName("dnsserver");
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setUrl(String url) {
this.url = url;
}
public void setProvider(DnsProviderType provider) {
this.provider = provider;
}
public void setPublic(Boolean value) {
isPublic = value;
}
public void setPort(Integer port) {
this.port = port;
}
public void setPublicDomainSuffix(String publicDomainSuffix) {
this.publicDomainSuffix = publicDomainSuffix;
}
public void setNameServers(List<String> nameServers) {
this.nameServers = nameServers;
}
}

View File

@ -25,7 +25,7 @@ public interface DnsProvider extends Adapter {
DnsProviderType getProviderType();
// Validates connectivity to the server
boolean validate(DnsServer server);
boolean validate(DnsServer server) throws Exception;
// Zone Operations
boolean createZone(DnsServer server, DnsZone zone);

View File

@ -28,6 +28,7 @@ import org.apache.cloudstack.api.command.user.dns.DeleteDnsZoneCmd;
import org.apache.cloudstack.api.command.user.dns.ListDnsRecordsCmd;
import org.apache.cloudstack.api.command.user.dns.ListDnsServersCmd;
import org.apache.cloudstack.api.command.user.dns.ListDnsZonesCmd;
import org.apache.cloudstack.api.command.user.dns.UpdateDnsServerCmd;
import org.apache.cloudstack.api.response.DnsRecordResponse;
import org.apache.cloudstack.api.response.DnsServerResponse;
import org.apache.cloudstack.api.response.DnsZoneResponse;
@ -40,6 +41,7 @@ public interface DnsProviderManager extends Manager, PluggableService {
DnsServer addDnsServer(AddDnsServerCmd cmd);
ListResponse<DnsServerResponse> listDnsServers(ListDnsServersCmd cmd);
DnsServer updateDnsServer(UpdateDnsServerCmd cmd);
boolean deleteDnsServer(DeleteDnsServerCmd cmd);
DnsServerResponse createDnsServerResponse(DnsServer server);

View File

@ -33,7 +33,7 @@ public interface DnsServer extends InternalIdentity, Identity {
DnsProviderType getProviderType();
String getAPIKey();
String getApiKey();
long getAccountId();

View File

@ -60,8 +60,11 @@ CREATE TABLE `cloud`.`dns_server` (
`id` bigint unsigned NOT NULL AUTO_INCREMENT COMMENT 'id of the dns server',
`uuid` varchar(255) COMMENT 'uuid of the dns server',
`name` varchar(255) NOT NULL COMMENT 'display name of the dns server',
`provider_type` varchar(255) NOT NULL COMMENT 'Provider type such as PowerDns',
`url` varchar(1024) NOT NULL COMMENT 'dns server url',
`api_key` varchar(255) NOT NULL COMMENT 'dns server api_key',
`port` int(11) DEFAULT NULL COMMENT 'optional dns server port',
`name_servers` varchar(1024) DEFAULT NULL COMMENT 'Comma separated list of name servers',
`is_public` tinyint(1) NOT NULL DEFAULT '0',
`public_domain_suffix` VARCHAR(255),
`state` ENUM('Enabled', 'Disabled') NOT NULL DEFAULT 'Disabled',

View File

@ -0,0 +1,118 @@
// 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.dns.powerdns;
import java.io.IOException;
import org.apache.http.HttpStatus;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.cloud.utils.exception.CloudRuntimeException;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
public class PowerDnsClient implements AutoCloseable {
public static final Logger logger = LoggerFactory.getLogger(PowerDnsClient.class);
private static final ObjectMapper MAPPER = new ObjectMapper();
private static final int TIMEOUT_MS = 5000;
private final CloseableHttpClient httpClient;
public void validate(String baseUrl, String apiKey) {
String normalizedUrl = baseUrl.trim();
if (!normalizedUrl.startsWith("http://") && !normalizedUrl.startsWith("https://")) {
normalizedUrl = "http://" + normalizedUrl; // default to HTTP
}
if (normalizedUrl.endsWith("/")) {
normalizedUrl = normalizedUrl.substring(0, normalizedUrl.length() - 1);
}
String checkUrl = normalizedUrl + "/api/v1/servers";
HttpGet request = new HttpGet(checkUrl);
request.addHeader("X-API-Key", apiKey);
request.addHeader("Accept", "application/json");
try (CloseableHttpResponse response = httpClient.execute(request)) {
int statusCode = response.getStatusLine().getStatusCode();
String body = response.getEntity() != null
? EntityUtils.toString(response.getEntity())
: null;
if (statusCode == HttpStatus.SC_OK) {
JsonNode root = MAPPER.readTree(body);
if (!root.isArray() || root.isEmpty()) {
throw new CloudRuntimeException("No servers returned by PowerDNS API");
}
boolean authoritativeFound = false;
for (JsonNode node : root) {
if ("authoritative".equalsIgnoreCase(node.path("daemon_type").asText(null))) {
authoritativeFound = true;
break;
}
}
if (!authoritativeFound) {
throw new CloudRuntimeException("No authoritative PowerDNS server found");
}
} else if (statusCode == HttpStatus.SC_UNAUTHORIZED || statusCode == HttpStatus.SC_FORBIDDEN) {
throw new CloudRuntimeException("Invalid PowerDNS API key");
} else {
logger.debug("Unexpected PowerDNS response: HTTP {} Body: {}", statusCode, body);
throw new CloudRuntimeException(String.format("PowerDNS validation failed with HTTP %d", statusCode));
}
} catch (IOException ex) {
throw new CloudRuntimeException("Failed to connect to PowerDNS", ex);
}
}
public PowerDnsClient() {
RequestConfig config = RequestConfig.custom()
.setConnectTimeout(TIMEOUT_MS)
.setConnectionRequestTimeout(TIMEOUT_MS)
.setSocketTimeout(TIMEOUT_MS)
.build();
this.httpClient = HttpClientBuilder.create()
.setDefaultRequestConfig(config)
.disableCookieManagement()
.build();
}
@Override
public void close() {
try {
httpClient.close();
} catch (IOException e) {
logger.warn("Failed to close PowerDNS HTTP client", e);
}
}
}

View File

@ -18,6 +18,7 @@
package org.apache.cloudstack.dns.powerdns;
import java.util.List;
import java.util.Map;
import org.apache.cloudstack.dns.DnsProvider;
import org.apache.cloudstack.dns.DnsProviderType;
@ -25,17 +26,28 @@ import org.apache.cloudstack.dns.DnsRecord;
import org.apache.cloudstack.dns.DnsServer;
import org.apache.cloudstack.dns.DnsZone;
import com.cloud.utils.StringUtils;
import com.cloud.utils.component.AdapterBase;
public class PowerDnsProvider extends AdapterBase implements DnsProvider {
private PowerDnsClient client;
@Override
public DnsProviderType getProviderType() {
return DnsProviderType.PowerDNS;
}
@Override
public boolean validate(DnsServer server) {
return false;
if (StringUtils.isBlank(server.getUrl())) {
throw new IllegalArgumentException("PowerDNS API URL cannot be empty");
}
if (StringUtils.isBlank(server.getApiKey())) {
throw new IllegalArgumentException("PowerDNS API key cannot be empty");
}
client.validate(server.getUrl(), server.getApiKey());
logger.debug("PowerDNS credentials validated for {}", server.getUrl());
return true;
}
@Override
@ -67,4 +79,20 @@ public class PowerDnsProvider extends AdapterBase implements DnsProvider {
public List<DnsRecord> listRecords(DnsServer server, DnsZone zone) {
return List.of();
}
@Override
public boolean configure(String name, Map<String, Object> params) {
if (client == null) {
client = new PowerDnsClient();
}
return true;
}
@Override
public boolean stop() {
if (client != null) {
client.close();
}
return true;
}
}

View File

@ -20,6 +20,8 @@ package org.apache.cloudstack.dns;
import java.util.ArrayList;
import java.util.List;
import javax.inject.Inject;
import org.apache.cloudstack.api.command.user.dns.AddDnsServerCmd;
import org.apache.cloudstack.api.command.user.dns.CreateDnsRecordCmd;
import org.apache.cloudstack.api.command.user.dns.CreateDnsZoneCmd;
@ -30,19 +32,33 @@ import org.apache.cloudstack.api.command.user.dns.ListDnsProvidersCmd;
import org.apache.cloudstack.api.command.user.dns.ListDnsRecordsCmd;
import org.apache.cloudstack.api.command.user.dns.ListDnsServersCmd;
import org.apache.cloudstack.api.command.user.dns.ListDnsZonesCmd;
import org.apache.cloudstack.api.command.user.dns.UpdateDnsServerCmd;
import org.apache.cloudstack.api.response.DnsRecordResponse;
import org.apache.cloudstack.api.response.DnsServerResponse;
import org.apache.cloudstack.api.response.DnsZoneResponse;
import org.apache.cloudstack.api.response.ListResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.dns.dao.DnsServerDao;
import org.apache.cloudstack.dns.vo.DnsServerVO;
import org.springframework.stereotype.Component;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.exception.PermissionDeniedException;
import com.cloud.user.Account;
import com.cloud.user.AccountManager;
import com.cloud.utils.Pair;
import com.cloud.utils.component.ManagerBase;
import com.cloud.utils.component.PluggableService;
import com.cloud.utils.db.Filter;
import com.cloud.utils.exception.CloudRuntimeException;
@Component
public class DnsProviderManagerImpl extends ManagerBase implements DnsProviderManager, PluggableService {
List<DnsProvider> dnsProviders;
@Inject
AccountManager accountMgr;
@Inject
DnsServerDao dnsServerDao;
private DnsProvider getProvider(DnsProviderType type) {
if (type == null) {
@ -58,22 +74,150 @@ public class DnsProviderManagerImpl extends ManagerBase implements DnsProviderMa
@Override
public DnsServer addDnsServer(AddDnsServerCmd cmd) {
return null;
Account caller = CallContext.current().getCallingAccount();
DnsServer existing = dnsServerDao.findByUrlAndAccount(cmd.getUrl(), caller.getId());
if (existing != null) {
throw new InvalidParameterValueException(
"This Account already has a DNS Server integration for URL: " + cmd.getUrl());
}
DnsProviderType type = DnsProviderType.fromString(cmd.getProvider());
DnsProvider provider = getProvider(type);
DnsServerVO server = new DnsServerVO(cmd.getName(), cmd.getUrl(), type, cmd.getCredentials(), cmd.getPort(),
cmd.isPublic(), cmd.getPublicDomainSuffix(), cmd.getNameServers(), caller.getId());
try {
provider.validate(server);
} catch (Exception ex) {
logger.error("Failed to validate DNS server", ex);
throw new CloudRuntimeException("Failed to validate DNS server");
}
return dnsServerDao.persist(server);
}
@Override
public ListResponse<DnsServerResponse> listDnsServers(ListDnsServersCmd cmd) {
return null;
Account caller = CallContext.current().getCallingAccount();
Long accountIdFilter = null;
if (accountMgr.isRootAdmin(caller.getId())) {
// Root Admin: Can see all, unless they specifically ask for an account
if (cmd.getAccountName() != null) {
Account target = accountMgr.getActiveAccountByName(cmd.getAccountName(), cmd.getDomainId());
if (target == null) {
return new ListResponse<>(); // Account not found
}
accountIdFilter = target.getId();
}
} else {
// Regular User / Domain Admin: STRICTLY restricted to their own account
accountIdFilter = caller.getId();
}
Filter searchFilter = new Filter(DnsServerVO.class, "id", true, cmd.getStartIndex(), cmd.getPageSizeVal());
Pair<List<DnsServerVO>, Integer> result = dnsServerDao.searchDnsServers(cmd.getId(), cmd.getKeyword(),
cmd.getProvider(), accountIdFilter, searchFilter);
ListResponse<DnsServerResponse> response = new ListResponse<>();
List<DnsServerResponse> serverResponses = new ArrayList<>();
for (DnsServerVO server : result.first()) {
serverResponses.add(createDnsServerResponse(server));
}
response.setResponses(serverResponses, result.second());
return response;
}
@Override
public DnsServer updateDnsServer(UpdateDnsServerCmd cmd) {
Long dnsServerId = cmd.getId();
DnsServerVO dnsServer = dnsServerDao.findById(dnsServerId);
if (dnsServer == null) {
throw new InvalidParameterValueException(String.format("DNS Server with ID: %s not found.", dnsServerId));
}
Account caller = CallContext.current().getCallingAccount();
if (!accountMgr.isRootAdmin(caller.getId()) && dnsServer.getAccountId() != caller.getId()) {
throw new PermissionDeniedException("You do not have permission to update this DNS server.");
}
boolean validationRequired = false;
String originalUrl = dnsServer.getUrl();
String originalKey = dnsServer.getApiKey();
if (cmd.getName() != null) {
dnsServer.setName(cmd.getName());
}
if (cmd.getUrl() != null) {
if (!cmd.getUrl().equals(originalUrl)) {
DnsServer duplicate = dnsServerDao.findByUrlAndAccount(cmd.getUrl(), dnsServer.getAccountId());
if (duplicate != null && duplicate.getId() != dnsServer.getId()) {
throw new InvalidParameterValueException("Another DNS Server with this URL already exists.");
}
dnsServer.setUrl(cmd.getUrl());
validationRequired = true;
}
}
if (cmd.getCredentials() != null && !cmd.getCredentials().equals(originalKey)) {
dnsServer.setApiKey(cmd.getCredentials());
validationRequired = true;
}
if (cmd.getPort() != null) {
dnsServer.setPort(cmd.getPort());
}
if (cmd.isPublic() != null) {
dnsServer.setIsPublic(cmd.isPublic());
}
if (cmd.getPublicDomainSuffix() != null) {
dnsServer.setPublicDomainSuffix(cmd.getPublicDomainSuffix());
}
if (cmd.getNameServers() != null) {
dnsServer.setNameServers(cmd.getNameServers());
}
if (validationRequired) {
DnsProvider provider = getProvider(dnsServer.getProviderType());
try {
provider.validate(dnsServer);
} catch (Exception ex) {
logger.error("Validation failed for DNS server", ex);
throw new InvalidParameterValueException("Validation failed for DNS server");
}
}
boolean updateStatus = dnsServerDao.update(dnsServerId, dnsServer);
if (updateStatus) {
return dnsServerDao.findById(dnsServerId);
} else {
throw new CloudRuntimeException(String.format("Unable to update DNS server: %s", dnsServer.getName()));
}
}
@Override
public boolean deleteDnsServer(DeleteDnsServerCmd cmd) {
return false;
Long dnsServerId = cmd.getId();
DnsServerVO dnsServer = dnsServerDao.findById(dnsServerId);
if (dnsServer == null) {
throw new InvalidParameterValueException(String.format("DNS Server with ID: %s not found.", dnsServerId));
}
Account caller = CallContext.current().getCallingAccount();
if (!accountMgr.isRootAdmin(caller.getId()) && dnsServer.getAccountId() != caller.getId()) {
throw new PermissionDeniedException("You do not have permission to delete this DNS server.");
}
return dnsServerDao.remove(dnsServerId);
}
@Override
public DnsServerResponse createDnsServerResponse(DnsServer server) {
return null;
DnsServerResponse response = new DnsServerResponse();
response.setId(server.getUuid());
response.setName(server.getName());
response.setUrl(server.getUrl());
response.setProvider(server.getProviderType());
response.setPublic(server.isPublic());
response.setObjectName("dnsserver");
return response;
}
@Override
@ -155,11 +299,13 @@ public class DnsProviderManagerImpl extends ManagerBase implements DnsProviderMa
@Override
public List<Class<?>> getCommands() {
List<Class<?>> cmdList = new ArrayList<>();
cmdList.add(ListDnsProvidersCmd.class);
// DNS Server Commands
cmdList.add(AddDnsServerCmd.class);
cmdList.add(ListDnsServersCmd.class);
cmdList.add(DeleteDnsServerCmd.class);
cmdList.add(ListDnsProvidersCmd.class);
cmdList.add(UpdateDnsServerCmd.class);
// DNS Zone Commands
cmdList.add(CreateDnsZoneCmd.class);

View File

@ -19,12 +19,18 @@ package org.apache.cloudstack.dns.dao;
import java.util.List;
import org.apache.cloudstack.dns.DnsServer;
import org.apache.cloudstack.dns.vo.DnsServerVO;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDao;
public interface DnsServerDao extends GenericDao<DnsServerVO, Long> {
List<DnsServerVO> listByProviderType(String providerType);
List<DnsServerVO> listByProvider(String provider);
DnsServer findByUrlAndAccount(String url, long accountId);
Pair<List<DnsServerVO>, Integer> searchDnsServers(Long id, String keyword, String provider, Long accountId, Filter filter);
}

View File

@ -19,29 +19,74 @@ package org.apache.cloudstack.dns.dao;
import java.util.List;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.dns.DnsServer;
import org.apache.cloudstack.dns.vo.DnsServerVO;
import org.springframework.stereotype.Component;
import com.cloud.utils.Pair;
import com.cloud.utils.db.Filter;
import com.cloud.utils.db.GenericDaoBase;
import com.cloud.utils.db.SearchBuilder;
import com.cloud.utils.db.SearchCriteria;
@Component
public class DnsServerDaoImpl extends GenericDaoBase<DnsServerVO, Long> implements DnsServerDao {
static final String PROVIDER_TYPE = "providerType";
SearchBuilder<DnsServerVO> AllFieldsSearch;
SearchBuilder<DnsServerVO> ProviderSearch;
SearchBuilder<DnsServerVO> AccountUrlSearch;
public DnsServerDaoImpl() {
super();
ProviderSearch = createSearchBuilder();
ProviderSearch.and(PROVIDER_TYPE, ProviderSearch.entity().getProviderType(), SearchCriteria.Op.EQ);
ProviderSearch.and(ApiConstants.PROVIDER_TYPE, ProviderSearch.entity().getProviderType(), SearchCriteria.Op.EQ);
ProviderSearch.done();
AccountUrlSearch = createSearchBuilder();
AccountUrlSearch.and(ApiConstants.URL, AccountUrlSearch.entity().getUrl(), SearchCriteria.Op.EQ);
AccountUrlSearch.and(ApiConstants.ACCOUNT_ID, AccountUrlSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
AccountUrlSearch.done();
AllFieldsSearch = createSearchBuilder();
AllFieldsSearch.and(ApiConstants.ID, AllFieldsSearch.entity().getId(), SearchCriteria.Op.EQ);
AllFieldsSearch.and(ApiConstants.NAME, AllFieldsSearch.entity().getName(), SearchCriteria.Op.LIKE);
AllFieldsSearch.and(ApiConstants.PROVIDER_TYPE, AllFieldsSearch.entity().getProviderType(), SearchCriteria.Op.EQ);
AllFieldsSearch.and(ApiConstants.ACCOUNT_ID, AllFieldsSearch.entity().getAccountId(), SearchCriteria.Op.EQ);
AllFieldsSearch.done();
}
@Override
public List<DnsServerVO> listByProviderType(String providerType) {
public List<DnsServerVO> listByProvider(String providerType) {
SearchCriteria<DnsServerVO> sc = ProviderSearch.create();
sc.setParameters(PROVIDER_TYPE, providerType);
sc.setParameters(ApiConstants.PROVIDER_TYPE, providerType);
return listBy(sc);
}
@Override
public DnsServer findByUrlAndAccount(String url, long accountId) {
SearchCriteria<DnsServerVO> sc = AccountUrlSearch.create();
sc.setParameters(ApiConstants.URL, url);
sc.setParameters(ApiConstants.ACCOUNT_ID, accountId);
return findOneBy(sc);
}
@Override
public Pair<List<DnsServerVO>, Integer> searchDnsServers(Long id, String keyword, String provider, Long accountId, Filter filter) {
SearchCriteria<DnsServerVO> sc = AllFieldsSearch.create();
if (id != null) {
sc.setParameters(ApiConstants.ID, id);
}
if (keyword != null) {
sc.setParameters(ApiConstants.NAME, "%" + keyword + "%");
}
if (provider != null) {
sc.setParameters(ApiConstants.PROVIDER_TYPE, provider);
}
if (accountId != null) {
sc.setParameters(ApiConstants.ACCOUNT_ID, accountId);
}
return searchAndCount(sc, filter);
}
}

View File

@ -54,6 +54,9 @@ public class DnsServerVO implements DnsServer {
@Column(name = "url")
private String url;
@Column(name = "port")
private Integer port;
@Column(name = "provider_type")
@Enumerated(EnumType.STRING)
private DnsProviderType providerType;
@ -75,6 +78,9 @@ public class DnsServerVO implements DnsServer {
@Column(name = "account_id")
private long accountId;
@Column(name = "name_servers")
private String nameServers;
@Column(name = GenericDao.CREATED_COLUMN)
@Temporal(value = TemporalType.TIMESTAMP)
private Date created = null;
@ -83,19 +89,25 @@ public class DnsServerVO implements DnsServer {
@Temporal(value = TemporalType.TIMESTAMP)
private Date removed = null;
public DnsServerVO() {
DnsServerVO() {
this.uuid = UUID.randomUUID().toString();
this.created = new Date();
}
public DnsServerVO(String name, String url, DnsProviderType providerType, String apiKey, long accountId, boolean isPublic) {
public DnsServerVO(String name, String url, DnsProviderType providerType, String apiKey,
Integer port, boolean isPublic, String publicDomainSuffix, String nameServers,
long accountId) {
this();
this.name = name;
this.url = url;
this.port = port;
this.providerType = providerType;
this.apiKey = apiKey;
this.accountId = accountId;
this.publicDomainSuffix = publicDomainSuffix;
this.nameServers = nameServers;
this.isPublic = isPublic;
this.state = State.Enabled;
}
@Override
@ -119,7 +131,7 @@ public class DnsServerVO implements DnsServer {
}
@Override
public String getAPIKey() {
public String getApiKey() {
return apiKey;
}
@ -154,4 +166,42 @@ public class DnsServerVO implements DnsServer {
public void setState(State state) {
this.state = state;
}
@Override
public String toString() {
return "DnsServerVO {" +
"id=" + id +
", name='" + name + '\'' +
", url='" + url + '\'' +
", apiKey='*****'" +
"}";
}
public void setNameServers(String nameServers) {
this.nameServers = nameServers;
}
public void setIsPublic(boolean value) {
isPublic = value;
}
public void setPublicDomainSuffix(String publicDomainSuffix) {
this.publicDomainSuffix = publicDomainSuffix;
}
public void setApiKey(String apiKey) {
this.apiKey = apiKey;
}
public void setPort(Integer port) {
this.port = port;
}
public void setUrl(String url) {
this.url = url;
}
public void setName(String name) {
this.name = name;
}
}