Skip to content

Commit f29b8be

Browse files
committed
following dns zone apis are integrated:
1. creatednszone 2. listdnszone 3. updatednszone 4. deletednszone
1 parent df21318 commit f29b8be

13 files changed

Lines changed: 302 additions & 92 deletions

File tree

api/src/main/java/org/apache/cloudstack/api/command/user/dns/DeleteDnsZoneCmd.java

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -23,8 +23,7 @@ public class DeleteDnsZoneCmd extends BaseAsyncCmd {
2323
//////////////// API Parameters /////////////////////
2424
/////////////////////////////////////////////////////
2525

26-
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = DnsZoneResponse.class,
27-
required = true, description = "the ID of the DNS zone")
26+
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = DnsZoneResponse.class, required = true, description = "The ID of the DNS zone")
2827
private Long id;
2928

3029
/////////////////////////////////////////////////////
@@ -42,9 +41,7 @@ public Long getId() {
4241
@Override
4342
public void execute() {
4443
try {
45-
// The Manager handles both DB removal and Plugin execution
46-
boolean result = dnsProviderManager.deleteDnsZone(this);
47-
44+
boolean result = dnsProviderManager.deleteDnsZone(getId());
4845
if (result) {
4946
SuccessResponse response = new SuccessResponse(getCommandName());
5047
setResponseObject(response);
@@ -74,7 +71,7 @@ public long getEntityOwnerId() {
7471

7572
@Override
7673
public String getEventType() {
77-
return EventTypes.EVENT_DNS_ZONE_DELETE; // Ensure this constant is added to EventTypes
74+
return EventTypes.EVENT_DNS_ZONE_DELETE;
7875
}
7976

8077
@Override

api/src/main/java/org/apache/cloudstack/api/command/user/dns/ListDnsZonesCmd.java

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -7,9 +7,8 @@
77
import org.apache.cloudstack.api.response.DnsServerResponse;
88
import org.apache.cloudstack.api.response.DnsZoneResponse;
99
import org.apache.cloudstack.api.response.ListResponse;
10-
import org.apache.cloudstack.api.response.NetworkResponse;
1110

12-
@APICommand(name = "listDnsZones", description = "Lists DNS Zones.",
11+
@APICommand(name = "listDnsZones", description = "Lists DNS zones.",
1312
responseObject = DnsZoneResponse.class,
1413
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
1514
public class ListDnsZonesCmd extends BaseListAccountResourcesCmd {
@@ -20,20 +19,19 @@ public class ListDnsZonesCmd extends BaseListAccountResourcesCmd {
2019
/////////////////////////////////////////////////////
2120
///
2221
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = DnsZoneResponse.class,
23-
description = "list DNS zone by ID")
22+
description = "List DNS zone by ID")
2423
private Long id;
2524

2625
@Parameter(name = "dnsserverid", type = CommandType.UUID, entityType = DnsServerResponse.class,
27-
description = "list DNS zones belonging to a specific DNS Server")
26+
description = "List DNS zones belonging to a specific DNS server")
2827
private Long dnsServerId;
2928

30-
@Parameter(name = ApiConstants.NETWORK_ID, type = CommandType.UUID, entityType = NetworkResponse.class,
31-
description = "list DNS zones associated with a specific Network")
32-
private Long networkId;
29+
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, description = "List by zone name")
30+
private String name;
3331

3432
public Long getId() { return id; }
3533
public Long getDnsServerId() { return dnsServerId; }
36-
public Long getNetworkId() { return networkId; }
34+
public String getName() { return name; }
3735

3836
@Override
3937
public void execute() {
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
package org.apache.cloudstack.api.command.user.dns;
2+
3+
import javax.inject.Inject;
4+
5+
import org.apache.cloudstack.api.APICommand;
6+
import org.apache.cloudstack.api.ApiConstants;
7+
import org.apache.cloudstack.api.ApiErrorCode;
8+
import org.apache.cloudstack.api.BaseCmd;
9+
import org.apache.cloudstack.api.Parameter;
10+
import org.apache.cloudstack.api.ServerApiException;
11+
import org.apache.cloudstack.api.response.DnsZoneResponse;
12+
import org.apache.cloudstack.context.CallContext;
13+
import org.apache.cloudstack.dns.DnsProviderManager;
14+
import org.apache.cloudstack.dns.DnsZone;
15+
16+
@APICommand(name = "updateDnsZone", description = "Updates a DNS Zone's metadata",
17+
responseObject = DnsZoneResponse.class,
18+
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
19+
public class UpdateDnsZoneCmd extends BaseCmd {
20+
21+
private static final String COMMAND_RESPONSE_NAME = "updatednszoneresponse";
22+
23+
@Inject
24+
DnsProviderManager dnsProviderManager;
25+
26+
/////////////////////////////////////////////////////
27+
//////////////// API Parameters /////////////////////
28+
/////////////////////////////////////////////////////
29+
30+
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = DnsZoneResponse.class,
31+
required = true, description = "The ID of the DNS zone")
32+
private Long id;
33+
34+
@Parameter(name = ApiConstants.DESCRIPTION, type = CommandType.STRING, description = "Display text for the zone")
35+
private String description;
36+
37+
/////////////////////////////////////////////////////
38+
/////////////////// Accessors ///////////////////////
39+
/////////////////////////////////////////////////////
40+
41+
public String getDescription() {
42+
return description;
43+
}
44+
45+
public Long getId() {
46+
return id;
47+
}
48+
49+
/////////////////////////////////////////////////////
50+
/////////////// Implementation //////////////////////
51+
/////////////////////////////////////////////////////
52+
53+
@Override
54+
public void execute() {
55+
try {
56+
DnsZone result = dnsProviderManager.updateDnsZone(this);
57+
if (result != null) {
58+
DnsZoneResponse response = dnsProviderManager.createDnsZoneResponse(result);
59+
response.setResponseName(getCommandName());
60+
setResponseObject(response);
61+
} else {
62+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update DNS Zone on external provider");
63+
}
64+
} catch (Exception e) {
65+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update DNS Zone: " + e.getMessage());
66+
}
67+
}
68+
69+
@Override
70+
public String getCommandName() {
71+
return COMMAND_RESPONSE_NAME;
72+
}
73+
74+
@Override
75+
public long getEntityOwnerId() {
76+
return CallContext.current().getCallingAccount().getId();
77+
}
78+
}

api/src/main/java/org/apache/cloudstack/api/response/DnsZoneResponse.java

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,10 @@ public class DnsZoneResponse extends BaseResponse {
5959
@Param(description = "The state of the zone (Active/Inactive)")
6060
private DnsZone.State state;
6161

62+
@SerializedName(ApiConstants.DESCRIPTION)
63+
@Param(description = "Description for the DNS zone")
64+
private String description;
65+
6266
public DnsZoneResponse() {
6367
super();
6468
setObjectName("dnszone");
@@ -91,4 +95,12 @@ public void setType(DnsZone.ZoneType type) {
9195
public void setState(DnsZone.State state) {
9296
this.state = state;
9397
}
98+
99+
public void setId(String id) {
100+
this.id = id;
101+
}
102+
103+
public void setDescription(String description) {
104+
this.description = description;
105+
}
94106
}

api/src/main/java/org/apache/cloudstack/dns/DnsProvider.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,11 @@ public interface DnsProvider extends Adapter {
2525
DnsProviderType getProviderType();
2626

2727
// Validates connectivity to the server
28-
boolean validate(DnsServer server) throws Exception;
28+
void validate(DnsServer server) throws Exception;
2929

3030
// Zone Operations
31-
boolean provisionZone(DnsServer server, DnsZone zone) throws Exception;
32-
boolean deleteZone(DnsServer server, DnsZone zone);
31+
void provisionZone(DnsServer server, DnsZone zone);
32+
void deleteZone(DnsServer server, DnsZone zone) ;
3333

3434
DnsRecord createRecord(DnsServer server, DnsZone zone, DnsRecord record);
3535
boolean updateRecord(DnsServer server, DnsZone zone, DnsRecord record);

api/src/main/java/org/apache/cloudstack/dns/DnsProviderManager.java

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,11 +24,11 @@
2424
import org.apache.cloudstack.api.command.user.dns.CreateDnsZoneCmd;
2525
import org.apache.cloudstack.api.command.user.dns.DeleteDnsRecordCmd;
2626
import org.apache.cloudstack.api.command.user.dns.DeleteDnsServerCmd;
27-
import org.apache.cloudstack.api.command.user.dns.DeleteDnsZoneCmd;
2827
import org.apache.cloudstack.api.command.user.dns.ListDnsRecordsCmd;
2928
import org.apache.cloudstack.api.command.user.dns.ListDnsServersCmd;
3029
import org.apache.cloudstack.api.command.user.dns.ListDnsZonesCmd;
3130
import org.apache.cloudstack.api.command.user.dns.UpdateDnsServerCmd;
31+
import org.apache.cloudstack.api.command.user.dns.UpdateDnsZoneCmd;
3232
import org.apache.cloudstack.api.response.DnsRecordResponse;
3333
import org.apache.cloudstack.api.response.DnsServerResponse;
3434
import org.apache.cloudstack.api.response.DnsZoneResponse;
@@ -47,8 +47,14 @@ public interface DnsProviderManager extends Manager, PluggableService {
4747

4848
DnsServer getDnsServer(Long id);
4949

50-
DnsZone createDnsZone(CreateDnsZoneCmd cmd);
51-
boolean deleteDnsZone(DeleteDnsZoneCmd cmd);
50+
// Allocates the DB row (State: Inactive)
51+
DnsZone allocateDnsZone(CreateDnsZoneCmd cmd);
52+
// Calls the Plugin (State: Inactive -> Active)
53+
DnsZone provisionDnsZone(long zoneId);
54+
55+
DnsZone getDnsZone(Long id);
56+
DnsZone updateDnsZone(UpdateDnsZoneCmd cmd);
57+
boolean deleteDnsZone(Long id);
5258
ListResponse<DnsZoneResponse> listDnsZones(ListDnsZonesCmd cmd);
5359

5460
DnsZone getDnsZone(long id);
@@ -60,11 +66,6 @@ public interface DnsProviderManager extends Manager, PluggableService {
6066

6167
List<String> listProviderNames();
6268

63-
// Allocates the DB row (State: Inactive)
64-
DnsZone allocateDnsZone(CreateDnsZoneCmd cmd);
65-
66-
// Calls the Plugin (State: Inactive -> Active)
67-
DnsZone provisionDnsZone(long zoneId);
6869

6970
// Helper to create the response object
7071
DnsZoneResponse createDnsZoneResponse(DnsZone zone);

engine/schema/src/main/resources/META-INF/db/schema-42210to42300.sql

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,6 @@ CREATE TABLE `cloud`.`dns_zone` (
9292
`removed` datetime DEFAULT NULL COMMENT 'Date removed (soft delete)',
9393
PRIMARY KEY (`id`),
9494
CONSTRAINT `uc_dns_zone__uuid` UNIQUE (`uuid`),
95-
CONSTRAINT `uc_dns_zone__name_server_type` UNIQUE (`name`, `dns_server_id`, `type`),
9695
KEY `i_dns_zone__dns_server` (`dns_server_id`),
9796
KEY `i_dns_zone__account_id` (`account_id`),
9897
CONSTRAINT `fk_dns_zone__dns_server_id` FOREIGN KEY (`dns_server_id`) REFERENCES `dns_server` (`id`) ON DELETE CASCADE,

plugins/dns/powerdns/src/main/java/org/apache/cloudstack/dns/powerdns/PowerDnsClient.java

Lines changed: 61 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,14 @@
1818
package org.apache.cloudstack.dns.powerdns;
1919

2020
import java.io.IOException;
21+
import java.net.URLEncoder;
22+
import java.nio.charset.StandardCharsets;
2123
import java.util.List;
2224

2325
import org.apache.http.HttpStatus;
2426
import org.apache.http.client.config.RequestConfig;
2527
import org.apache.http.client.methods.CloseableHttpResponse;
28+
import org.apache.http.client.methods.HttpDelete;
2629
import org.apache.http.client.methods.HttpGet;
2730
import org.apache.http.client.methods.HttpPost;
2831
import org.apache.http.entity.StringEntity;
@@ -45,16 +48,15 @@ public class PowerDnsClient implements AutoCloseable {
4548
private final CloseableHttpClient httpClient;
4649

4750
public void validate(String baseUrl, String apiKey) {
48-
String checkUrl = buildApiUrl(baseUrl, "/api/v1/servers");
51+
String checkUrl = buildApiUrl(baseUrl, "/servers");
4952
HttpGet request = new HttpGet(checkUrl);
5053
request.addHeader("X-API-Key", apiKey);
54+
request.addHeader("Content-Type", "application/json");
5155
request.addHeader("Accept", "application/json");
5256

5357
try (CloseableHttpResponse response = httpClient.execute(request)) {
5458
int statusCode = response.getStatusLine().getStatusCode();
55-
String body = response.getEntity() != null
56-
? EntityUtils.toString(response.getEntity())
57-
: null;
59+
String body = response.getEntity() != null ? EntityUtils.toString(response.getEntity()) : null;
5860

5961
if (statusCode == HttpStatus.SC_OK) {
6062
JsonNode root = MAPPER.readTree(body);
@@ -88,27 +90,25 @@ public void validate(String baseUrl, String apiKey) {
8890
}
8991

9092
public void createZone(String baseUrl, String apiKey, String zoneName, List<String> nameservers) {
91-
String url = buildApiUrl(baseUrl, "/servers/localhost/zones");
92-
ObjectNode json = MAPPER.createObjectNode();
93-
json.put("name", zoneName.endsWith(".") ? zoneName : zoneName + ".");
94-
json.put("kind", "Native");
95-
json.put("dnssec", false);
96-
97-
if (nameservers != null && !nameservers.isEmpty()) {
98-
ArrayNode nsArray = json.putArray("nameservers");
99-
for (String ns : nameservers) {
100-
nsArray.add(ns.endsWith(".") ? ns : ns + ".");
93+
String normalizedZone = zoneName.endsWith(".") ? zoneName : zoneName + ".";
94+
try {
95+
String url = buildApiUrl(baseUrl, "/servers/localhost/zones");
96+
ObjectNode json = MAPPER.createObjectNode();
97+
json.put("name", normalizedZone);
98+
json.put("kind", "Native");
99+
json.put("dnssec", false);
100+
101+
if (nameservers != null && !nameservers.isEmpty()) {
102+
ArrayNode nsArray = json.putArray("nameservers");
103+
for (String ns : nameservers) {
104+
nsArray.add(ns.endsWith(".") ? ns : ns + ".");
105+
}
101106
}
102-
}
103-
104-
logger.debug("Creating PowerDNS zone: {} using URL: {}", zoneName, url);
105-
106-
HttpPost request = new HttpPost(url);
107-
request.addHeader("X-API-Key", apiKey);
108-
request.addHeader("Content-Type", "application/json");
109-
request.addHeader("Accept", "application/json");
110107

111-
try {
108+
HttpPost request = new HttpPost(url);
109+
request.addHeader("X-API-Key", apiKey);
110+
request.addHeader("Content-Type", "application/json");
111+
request.addHeader("Accept", "application/json");
112112
request.setEntity(new StringEntity(json.toString()));
113113

114114
try (CloseableHttpResponse response = httpClient.execute(request)) {
@@ -127,21 +127,55 @@ public void createZone(String baseUrl, String apiKey, String zoneName, List<Stri
127127
throw new CloudRuntimeException("Zone already exists: " + zoneName);
128128
}
129129

130-
if (statusCode == HttpStatus.SC_UNAUTHORIZED ||
131-
statusCode == HttpStatus.SC_FORBIDDEN) {
130+
if (statusCode == HttpStatus.SC_UNAUTHORIZED || statusCode == HttpStatus.SC_FORBIDDEN) {
132131
throw new CloudRuntimeException("Invalid PowerDNS API key");
133132
}
134133

135134
logger.debug("Unexpected PowerDNS response: HTTP {} Body: {}", statusCode, body);
136-
137135
throw new CloudRuntimeException(String.format("Failed to create zone %s (HTTP %d)", zoneName, statusCode));
138136
}
139-
140137
} catch (IOException e) {
141138
throw new CloudRuntimeException("Error while creating PowerDNS zone " + zoneName, e);
142139
}
143140
}
144141

142+
public void deleteZone(String baseUrl, String apiKey, String zoneName) {
143+
String normalizedZone = zoneName.endsWith(".") ? zoneName : zoneName + ".";
144+
try {
145+
String encodedZone = URLEncoder.encode(normalizedZone, StandardCharsets.UTF_8);
146+
String url = buildApiUrl(baseUrl, "/servers/localhost/zones/" + encodedZone);
147+
HttpDelete request = new HttpDelete(url);
148+
request.addHeader("X-API-Key", apiKey);
149+
request.addHeader("Content-Type", "application/json");
150+
request.addHeader("Accept", "application/json");
151+
152+
try (CloseableHttpResponse response = httpClient.execute(request)) {
153+
154+
int statusCode = response.getStatusLine().getStatusCode();
155+
String body = response.getEntity() != null ? EntityUtils.toString(response.getEntity()) : null;
156+
157+
if (statusCode == HttpStatus.SC_NO_CONTENT) {
158+
logger.debug("Zone {} deleted successfully", normalizedZone);
159+
return;
160+
}
161+
162+
if (statusCode == HttpStatus.SC_NOT_FOUND) {
163+
logger.debug("Zone {} not found in PowerDNS", normalizedZone);
164+
return;
165+
}
166+
167+
if (statusCode == HttpStatus.SC_UNAUTHORIZED || statusCode == HttpStatus.SC_FORBIDDEN) {
168+
throw new CloudRuntimeException("Invalid PowerDNS API key");
169+
}
170+
171+
logger.debug("Unexpected PowerDNS response while deleting zone: HTTP {} Body: {}", statusCode, body);
172+
throw new CloudRuntimeException(String.format("Failed to delete zone %s (HTTP %d)", normalizedZone, statusCode));
173+
}
174+
} catch (IOException e) {
175+
throw new CloudRuntimeException("Error while deleting PowerDNS zone " + zoneName, e);
176+
}
177+
}
178+
145179

146180
public PowerDnsClient() {
147181
RequestConfig config = RequestConfig.custom()

0 commit comments

Comments
 (0)