mirror of https://github.com/apache/cloudstack.git
Changes done to AddDnsServer, ListDnsServer, DeleteDnsServer and UpdateDnsServer
This commit is contained in:
parent
6ef7f9bcd4
commit
9911c280e1
|
|
@ -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 " +
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(); }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -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());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
||||
|
|
|
|||
|
|
@ -33,7 +33,7 @@ public interface DnsServer extends InternalIdentity, Identity {
|
|||
|
||||
DnsProviderType getProviderType();
|
||||
|
||||
String getAPIKey();
|
||||
String getApiKey();
|
||||
|
||||
long getAccountId();
|
||||
|
||||
|
|
|
|||
|
|
@ -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',
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue