Skip to content

Commit 71720b3

Browse files
committed
Merge branch 'main' into 4.23-network-extension
2 parents 375aac3 + b3b9cad commit 71720b3

170 files changed

Lines changed: 16509 additions & 191 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

api/src/main/java/com/cloud/event/EventTypes.java

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,9 @@
3030
import org.apache.cloudstack.backup.BackupRepositoryService;
3131
import org.apache.cloudstack.config.Configuration;
3232
import org.apache.cloudstack.datacenter.DataCenterIpv4GuestSubnet;
33+
import org.apache.cloudstack.dns.DnsRecord;
34+
import org.apache.cloudstack.dns.DnsServer;
35+
import org.apache.cloudstack.dns.DnsZone;
3336
import org.apache.cloudstack.extension.Extension;
3437
import org.apache.cloudstack.extension.ExtensionCustomAction;
3538
import org.apache.cloudstack.gpu.GpuCard;
@@ -884,6 +887,17 @@ public class EventTypes {
884887
public static final String EVENT_BACKUP_REPOSITORY_ADD = "BACKUP.REPOSITORY.ADD";
885888
public static final String EVENT_BACKUP_REPOSITORY_UPDATE = "BACKUP.REPOSITORY.UPDATE";
886889

890+
// DNS Framework Events
891+
public static final String EVENT_DNS_SERVER_ADD = "DNS.SERVER.ADD";
892+
public static final String EVENT_DNS_SERVER_UPDATE = "DNS.SERVER.UPDATE";
893+
public static final String EVENT_DNS_SERVER_DELETE = "DNS.SERVER.DELETE";
894+
public static final String EVENT_DNS_ZONE_CREATE = "DNS.ZONE.CREATE";
895+
public static final String EVENT_DNS_ZONE_UPDATE = "DNS.ZONE.UPDATE";
896+
public static final String EVENT_DNS_ZONE_DELETE = "DNS.ZONE.DELETE";
897+
public static final String EVENT_DNS_RECORD_CREATE = "DNS.RECORD.CREATE";
898+
public static final String EVENT_DNS_RECORD_DELETE = "DNS.RECORD.DELETE";
899+
public static final String EVENT_DNS_NAME_COLLISION = "DNS.NAME.COLLISION";
900+
887901
static {
888902

889903
// TODO: need a way to force author adding event types to declare the entity details as well, with out braking
@@ -1442,6 +1456,17 @@ public class EventTypes {
14421456
// Backup Repository
14431457
entityEventDetails.put(EVENT_BACKUP_REPOSITORY_ADD, BackupRepositoryService.class);
14441458
entityEventDetails.put(EVENT_BACKUP_REPOSITORY_UPDATE, BackupRepositoryService.class);
1459+
1460+
// DNS Framework Events
1461+
entityEventDetails.put(EVENT_DNS_SERVER_ADD, DnsServer.class);
1462+
entityEventDetails.put(EVENT_DNS_SERVER_UPDATE, DnsServer.class);
1463+
entityEventDetails.put(EVENT_DNS_SERVER_DELETE, DnsServer.class);
1464+
entityEventDetails.put(EVENT_DNS_ZONE_CREATE, DnsZone.class);
1465+
entityEventDetails.put(EVENT_DNS_ZONE_UPDATE, DnsZone.class);
1466+
entityEventDetails.put(EVENT_DNS_ZONE_DELETE, DnsZone.class);
1467+
entityEventDetails.put(EVENT_DNS_RECORD_CREATE, DnsRecord.class);
1468+
entityEventDetails.put(EVENT_DNS_RECORD_DELETE, DnsRecord.class);
1469+
14451470
}
14461471

14471472
public static boolean isNetworkEvent(String eventType) {

api/src/main/java/com/cloud/vm/Nic.java

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,11 @@
3333
* Nic represents one nic on the VM.
3434
*/
3535
public interface Nic extends Identity, InternalIdentity {
36+
37+
interface Topics {
38+
String NIC_LIFECYCLE = "nic.lifecycle";
39+
}
40+
3641
enum Event {
3742
ReservationRequested, ReleaseRequested, CancelRequested, OperationCompleted, OperationFailed,
3843
}

api/src/main/java/org/apache/cloudstack/api/ApiConstants.java

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1386,6 +1386,38 @@ public class ApiConstants {
13861386
" a VR, CloudStack will use the same MAC address for the public NIC of all VRs. Otherwise, if \"false\", new public NICs will always have " +
13871387
" a new MAC address.";
13881388

1389+
// DNS provider related
1390+
public static final String NAME_SERVERS = "nameservers";
1391+
public static final String DNS_USER_NAME = "dnsusername";
1392+
public static final String DNS_API_KEY = "dnsapikey";
1393+
public static final String DNS_ZONE_ID = "dnszoneid";
1394+
public static final String DNS_ZONE = "dnszone";
1395+
public static final String DNS_RECORD = "dnsrecord";
1396+
public static final String DNS_SUB_DOMAIN = "dnssubdomain";
1397+
public static final String DNS_SERVER_ID = "dnsserverid";
1398+
public static final String CONTENT = "content";
1399+
public static final String CONTENTS = "contents";
1400+
public static final String PUBLIC_DOMAIN_SUFFIX = "publicdomainsuffix";
1401+
public static final String AUTHORITATIVE = "authoritative";
1402+
public static final String KIND = "kind";
1403+
public static final String DNS_SEC = "dnssec";
1404+
public static final String TTL = "ttl";
1405+
public static final String CHANGE_TYPE = "changetype";
1406+
public static final String RECORDS = "records";
1407+
public static final String RR_SETS = "rrsets";
1408+
public static final String X_API_KEY = "X-API-Key";
1409+
public static final String DISABLED = "disabled";
1410+
public static final String CONTENT_TYPE = "Content-Type";
1411+
public static final String NATIVE_ZONE = "Native";
1412+
public static final String NIC_DNS_NAME = "nicdnsname";
1413+
public static final String TIME_STAMP = "timestamp";
1414+
public static final String INSTANCE_ID = "instanceId";
1415+
public static final String OLD_STATE = "oldState";
1416+
public static final String NEW_STATE = "newState";
1417+
public static final String OLD_HOST_NAME = "oldHostName";
1418+
public static final String EXISTING = "existing";
1419+
public static final String UNMANAGE = "unmanage";
1420+
13891421
public static final String PARAMETER_DESCRIPTION_ACTIVATION_RULE = "Quota tariff's activation rule. It can receive a JS script that results in either " +
13901422
"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 " +
13911423
"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 " +
@@ -1467,7 +1499,7 @@ public String toString() {
14671499
}
14681500

14691501
public enum HostDetails {
1470-
all, capacity, events, stats, min;
1502+
all, capacity, core, events, stats, min;
14711503
}
14721504

14731505
public enum VMDetails {

api/src/main/java/org/apache/cloudstack/api/BaseCmd.java

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@
4040
import org.apache.cloudstack.alert.AlertService;
4141
import org.apache.cloudstack.annotation.AnnotationService;
4242
import org.apache.cloudstack.context.CallContext;
43+
import org.apache.cloudstack.dns.DnsProviderManager;
4344
import org.apache.cloudstack.gpu.GpuService;
4445
import org.apache.cloudstack.network.RoutedIpv4Manager;
4546
import org.apache.cloudstack.network.lb.ApplicationLoadBalancerService;
@@ -232,6 +233,9 @@ public static enum CommandType {
232233
@Inject
233234
public RoutedIpv4Manager routedIpv4Manager;
234235

236+
@Inject
237+
public DnsProviderManager dnsProviderManager;
238+
235239
public abstract void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
236240
ResourceAllocationException, NetworkRuleConflictException;
237241

Lines changed: 169 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,169 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.apache.cloudstack.api.command.user.dns;
19+
20+
import java.util.Collection;
21+
import java.util.HashMap;
22+
import java.util.List;
23+
import java.util.Map;
24+
25+
import org.apache.cloudstack.acl.RoleType;
26+
import org.apache.cloudstack.api.APICommand;
27+
import org.apache.cloudstack.api.ApiConstants;
28+
import org.apache.cloudstack.api.ApiErrorCode;
29+
import org.apache.cloudstack.api.BaseCmd;
30+
import org.apache.cloudstack.api.Parameter;
31+
import org.apache.cloudstack.api.ServerApiException;
32+
import org.apache.cloudstack.api.response.DnsServerResponse;
33+
import org.apache.cloudstack.context.CallContext;
34+
import org.apache.cloudstack.dns.DnsProviderType;
35+
import org.apache.cloudstack.dns.DnsServer;
36+
import org.apache.commons.collections.MapUtils;
37+
import org.apache.commons.lang3.BooleanUtils;
38+
39+
import com.cloud.exception.InvalidParameterValueException;
40+
import com.cloud.utils.EnumUtils;
41+
42+
@APICommand(name = "addDnsServer",
43+
description = "Adds a new external DNS server",
44+
responseObject = DnsServerResponse.class,
45+
entityType = {DnsServer.class},
46+
requestHasSensitiveInfo = true,
47+
responseHasSensitiveInfo = false,
48+
since = "4.23.0",
49+
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
50+
public class AddDnsServerCmd extends BaseCmd {
51+
52+
/////////////////////////////////////////////////////
53+
//////////////// API parameters /////////////////////
54+
/////////////////////////////////////////////////////
55+
///
56+
@Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Name of the DNS server")
57+
private String name;
58+
59+
@Parameter(name = ApiConstants.URL, type = CommandType.STRING, required = true, description = "API URL of the provider")
60+
private String url;
61+
62+
@Parameter(name = ApiConstants.PROVIDER, type = CommandType.STRING, required = true, description = "Provider type (e.g., PowerDNS)")
63+
private String provider;
64+
65+
@Parameter(name = ApiConstants.DNS_USER_NAME, type = CommandType.STRING,
66+
description = "Username or email associated with the DNS provider account (used for authentication)")
67+
private String dnsUserName;
68+
69+
@Parameter(name = ApiConstants.DNS_API_KEY, required = true, type = CommandType.STRING, description = "API key or token for the DNS provider")
70+
private String dnsApiKey;
71+
72+
@Parameter(name = ApiConstants.PORT, type = CommandType.INTEGER, description = "Port number of the external DNS server")
73+
private Integer port;
74+
75+
@Parameter(name = ApiConstants.IS_PUBLIC, type = CommandType.BOOLEAN,
76+
description = "Whether this DNS server can be used by accounts other than the owner to create and manage DNS zones")
77+
private Boolean isPublic;
78+
79+
@Parameter(name = ApiConstants.PUBLIC_DOMAIN_SUFFIX, type = CommandType.STRING,
80+
description = "Domain suffix that restricts DNS zones created by non-owner accounts to subdomains of this " +
81+
"suffix (for example, sub.example.com under example.com)")
82+
private String publicDomainSuffix;
83+
84+
@Parameter(name = ApiConstants.NAME_SERVERS, type = CommandType.LIST, collectionType = CommandType.STRING,
85+
required = true,
86+
description = "Comma separated list of name servers; used to create NS records for the DNS Zone (for example, ns1.example.com, ns2.example.com)")
87+
private List<String> nameServers;
88+
89+
@Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, description = "Details in key/value pairs using " +
90+
"format details[i].keyname=keyvalue. Example: details[0].pdnsServerId=localhost")
91+
protected Map details;
92+
93+
/////////////////////////////////////////////////////
94+
/////////////////// Accessors ///////////////////////
95+
/////////////////////////////////////////////////////
96+
97+
public String getName() { return name; }
98+
99+
public String getUrl() { return url; }
100+
101+
public String getDnsApiKey() {
102+
return dnsApiKey;
103+
}
104+
105+
public Integer getPort() {
106+
return port;
107+
}
108+
109+
public Boolean isPublic() {
110+
return BooleanUtils.isTrue(isPublic);
111+
}
112+
113+
public String getPublicDomainSuffix() {
114+
return publicDomainSuffix;
115+
}
116+
117+
public List<String> getNameServers() {
118+
return nameServers;
119+
}
120+
121+
public DnsProviderType getProvider() {
122+
DnsProviderType dnsProviderType = EnumUtils.getEnumIgnoreCase(DnsProviderType.class, provider, DnsProviderType.PowerDNS);
123+
if (dnsProviderType == null) {
124+
throw new InvalidParameterValueException(String.format("Invalid value passed for provider type, valid values are: %s",
125+
EnumUtils.listValues(DnsProviderType.values())));
126+
}
127+
return dnsProviderType;
128+
}
129+
130+
@Override
131+
public long getEntityOwnerId() {
132+
return CallContext.current().getCallingAccount().getId();
133+
}
134+
135+
@Override
136+
public void execute() {
137+
try {
138+
DnsServer server = dnsProviderManager.addDnsServer(this);
139+
if (server != null) {
140+
DnsServerResponse response = dnsProviderManager.createDnsServerResponse(server);
141+
response.setResponseName(getCommandName());
142+
setResponseObject(response);
143+
} else {
144+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add DNS server");
145+
}
146+
} catch (Exception ex) {
147+
logger.error("Failed to add DNS server", ex);
148+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
149+
}
150+
}
151+
152+
public String getDnsUserName() {
153+
return dnsUserName;
154+
}
155+
156+
public Map<String, String> getDetails() {
157+
Map<String, String> detailsMap = new HashMap<>();
158+
if (MapUtils.isNotEmpty(details)) {
159+
Collection<?> props = details.values();
160+
for (Object prop : props) {
161+
HashMap<String, String> detail = (HashMap<String, String>) prop;
162+
for (Map.Entry<String, String> entry: detail.entrySet()) {
163+
detailsMap.put(entry.getKey(),entry.getValue());
164+
}
165+
}
166+
}
167+
return detailsMap;
168+
}
169+
}
Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
// Licensed to the Apache Software Foundation (ASF) under one
2+
// or more contributor license agreements. See the NOTICE file
3+
// distributed with this work for additional information
4+
// regarding copyright ownership. The ASF licenses this file
5+
// to you under the Apache License, Version 2.0 (the
6+
// "License"); you may not use this file except in compliance
7+
// with the License. You may obtain a copy of the License at
8+
//
9+
// http://www.apache.org/licenses/LICENSE-2.0
10+
//
11+
// Unless required by applicable law or agreed to in writing,
12+
// software distributed under the License is distributed on an
13+
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
14+
// KIND, either express or implied. See the License for the
15+
// specific language governing permissions and limitations
16+
// under the License.
17+
18+
package org.apache.cloudstack.api.command.user.dns;
19+
20+
import org.apache.cloudstack.acl.RoleType;
21+
import org.apache.cloudstack.acl.SecurityChecker;
22+
import org.apache.cloudstack.api.ACL;
23+
import org.apache.cloudstack.api.APICommand;
24+
import org.apache.cloudstack.api.ApiConstants;
25+
import org.apache.cloudstack.api.ApiErrorCode;
26+
import org.apache.cloudstack.api.BaseCmd;
27+
import org.apache.cloudstack.api.Parameter;
28+
import org.apache.cloudstack.api.ServerApiException;
29+
import org.apache.cloudstack.api.response.DnsZoneNetworkMapResponse;
30+
import org.apache.cloudstack.api.response.DnsZoneResponse;
31+
import org.apache.cloudstack.api.response.NetworkResponse;
32+
33+
import com.cloud.exception.ConcurrentOperationException;
34+
import com.cloud.exception.InsufficientCapacityException;
35+
import com.cloud.exception.NetworkRuleConflictException;
36+
import com.cloud.exception.ResourceAllocationException;
37+
import com.cloud.exception.ResourceUnavailableException;
38+
import com.cloud.network.Network;
39+
import com.cloud.user.Account;
40+
41+
@APICommand(name = "associateDnsZoneToNetwork",
42+
description = "Associates a DNS Zone with a Network for VM auto-registration",
43+
responseObject = DnsZoneNetworkMapResponse.class,
44+
requestHasSensitiveInfo = false,
45+
responseHasSensitiveInfo = false,
46+
since = "4.23.0",
47+
authorized = {RoleType.Admin, RoleType.ResourceAdmin, RoleType.DomainAdmin, RoleType.User})
48+
public class AssociateDnsZoneToNetworkCmd extends BaseCmd {
49+
50+
@Parameter(name = ApiConstants.DNS_ZONE_ID, type = CommandType.UUID, entityType = DnsZoneResponse.class,
51+
required = true, description = "The ID of the DNS zone")
52+
private Long dnsZoneId;
53+
54+
@ACL(accessType = SecurityChecker.AccessType.OperateEntry)
55+
@Parameter(name = ApiConstants.NETWORK_ID, type = CommandType.UUID, entityType = NetworkResponse.class,
56+
required = true, description = "The ID of the network")
57+
private Long networkId;
58+
59+
@Parameter(name = "subdomain", type = CommandType.STRING,
60+
description = "Optional subdomain to append (e.g., 'dev' creates vm1.dev.example.com)")
61+
private String subDomain;
62+
63+
@Override
64+
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
65+
try {
66+
DnsZoneNetworkMapResponse response = dnsProviderManager.associateZoneToNetwork(this);
67+
response.setResponseName(getCommandName());
68+
setResponseObject(response);
69+
} catch (Exception e) {
70+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
71+
}
72+
}
73+
74+
@Override
75+
public long getEntityOwnerId() {
76+
Network network = _entityMgr.findById(Network.class, networkId);
77+
if (network != null) {
78+
return network.getAccountId();
79+
}
80+
return Account.ACCOUNT_ID_SYSTEM;
81+
}
82+
83+
public Long getDnsZoneId() {
84+
return dnsZoneId;
85+
}
86+
87+
public Long getNetworkId() {
88+
return networkId;
89+
}
90+
91+
public String getSubDomain() {
92+
return subDomain;
93+
}
94+
}

0 commit comments

Comments
 (0)