Skip to content

Commit 8acb090

Browse files
Nitin Kumar MaharanaDaanHoogland
authored andcommitted
CLOUDSTACK-9880: Expansion of Management IP Range. (#2048)
At present, The management IP range can only be expanded under the same subnet. According to existing range, either the last IP can be forward extended or the first IP can be backward extended. But we cannot add an entirely different range from the same subnet. So the expansion of range is subnet bound, which is fixed. But when the range gets exhausted and a user wants to deploy more system VMs, then the operation would fail. The purpose of this feature is to expand the range of management network IPs within the existing subnet. It can also delete and list the IP ranges. Please refer the FS here: https://cwiki.apache.org/confluence/display/CLOUDSTACK/Expansion+of+Management+IP+Range
1 parent 9179bd5 commit 8acb090

File tree

15 files changed

+836
-193
lines changed

15 files changed

+836
-193
lines changed

api/src/com/cloud/configuration/ConfigurationService.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,9 @@
1919
import java.util.List;
2020

2121
import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd;
22+
import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd;
2223
import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd;
24+
import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd;
2325
import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd;
2426
import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd;
2527
import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd;
@@ -160,6 +162,19 @@ public interface ConfigurationService {
160162
*/
161163
Pod createPod(long zoneId, String name, String startIp, String endIp, String gateway, String netmask, String allocationState);
162164

165+
/**
166+
* Creates a mutual exclusive IP range in the pod with same gateway, netmask.
167+
* @param cmd - The command specifying pod ID, start IP, end IP, gateway, netmask.
168+
* @return The new range if successful, null otherwise.
169+
*/
170+
Pod createPodIpRange(CreateManagementNetworkIpRangeCmd cmd);
171+
172+
/**
173+
* Deletes a mutually exclusive IP range in the pod.
174+
* @param cmd - The command specifying pod ID, start IP, end IP.
175+
*/
176+
void deletePodIpRange(DeleteManagementNetworkIpRangeCmd cmd) throws ResourceUnavailableException, ConcurrentOperationException;
177+
163178
/**
164179
* Edits a pod in the database. Will not allow you to edit pods that are being used anywhere in the system.
165180
*

api/src/com/cloud/dc/StorageNetworkIpRange.java

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,20 +21,19 @@
2121
import org.apache.cloudstack.api.InternalIdentity;
2222

2323
public interface StorageNetworkIpRange extends InfrastructureEntity, InternalIdentity, Identity {
24-
2524
Integer getVlan();
2625

27-
String getPodUuid();
26+
String getGateway();
27+
28+
String getNetmask();
2829

2930
String getStartIp();
3031

3132
String getEndIp();
3233

33-
String getNetworkUuid();
34-
3534
String getZoneUuid();
3635

37-
String getNetmask();
36+
String getPodUuid();
3837

39-
String getGateway();
38+
String getNetworkUuid();
4039
}

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

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,9 @@ public class EventTypes {
296296
public static final String EVENT_VLAN_IP_RANGE_DEDICATE = "VLAN.IP.RANGE.DEDICATE";
297297
public static final String EVENT_VLAN_IP_RANGE_RELEASE = "VLAN.IP.RANGE.RELEASE";
298298

299+
public static final String EVENT_MANAGEMENT_IP_RANGE_CREATE = "MANAGEMENT.IP.RANGE.CREATE";
300+
public static final String EVENT_MANAGEMENT_IP_RANGE_DELETE = "MANAGEMENT.IP.RANGE.DELETE";
301+
299302
public static final String EVENT_STORAGE_IP_RANGE_CREATE = "STORAGE.IP.RANGE.CREATE";
300303
public static final String EVENT_STORAGE_IP_RANGE_DELETE = "STORAGE.IP.RANGE.DELETE";
301304
public static final String EVENT_STORAGE_IP_RANGE_UPDATE = "STORAGE.IP.RANGE.UPDATE";
@@ -761,6 +764,9 @@ public class EventTypes {
761764
entityEventDetails.put(EVENT_VLAN_IP_RANGE_DEDICATE, Vlan.class);
762765
entityEventDetails.put(EVENT_VLAN_IP_RANGE_RELEASE, Vlan.class);
763766

767+
entityEventDetails.put(EVENT_MANAGEMENT_IP_RANGE_CREATE, Pod.class);
768+
entityEventDetails.put(EVENT_MANAGEMENT_IP_RANGE_DELETE, Pod.class);
769+
764770
entityEventDetails.put(EVENT_STORAGE_IP_RANGE_CREATE, StorageNetworkIpRange.class);
765771
entityEventDetails.put(EVENT_STORAGE_IP_RANGE_DELETE, StorageNetworkIpRange.class);
766772
entityEventDetails.put(EVENT_STORAGE_IP_RANGE_UPDATE, StorageNetworkIpRange.class);
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
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+
package org.apache.cloudstack.api.command.admin.network;
18+
19+
import org.apache.log4j.Logger;
20+
21+
import org.apache.cloudstack.acl.RoleType;
22+
import org.apache.cloudstack.api.ApiArgValidator;
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.BaseAsyncCmd;
27+
import org.apache.cloudstack.api.Parameter;
28+
import org.apache.cloudstack.api.ServerApiException;
29+
import org.apache.cloudstack.api.response.PodResponse;
30+
31+
import com.cloud.dc.Pod;
32+
import com.cloud.event.EventTypes;
33+
import com.cloud.exception.ConcurrentOperationException;
34+
import com.cloud.exception.InsufficientCapacityException;
35+
import com.cloud.exception.ResourceAllocationException;
36+
import com.cloud.exception.ResourceUnavailableException;
37+
import com.cloud.user.Account;
38+
39+
@APICommand(name = CreateManagementNetworkIpRangeCmd.APINAME,
40+
description = "Creates a Management network IP range.",
41+
responseObject = PodResponse.class,
42+
since = "4.11.0.0",
43+
requestHasSensitiveInfo = false,
44+
responseHasSensitiveInfo = false,
45+
authorized = {RoleType.Admin})
46+
public class CreateManagementNetworkIpRangeCmd extends BaseAsyncCmd {
47+
public static final Logger s_logger = Logger.getLogger(CreateManagementNetworkIpRangeCmd.class);
48+
49+
public static final String APINAME = "createManagementNetworkIpRange";
50+
51+
/////////////////////////////////////////////////////
52+
//////////////// API parameters /////////////////////
53+
/////////////////////////////////////////////////////
54+
@Parameter(name = ApiConstants.POD_ID,
55+
type = CommandType.UUID,
56+
entityType = PodResponse.class,
57+
required = true,
58+
description = "UUID of POD, where the IP range belongs to.",
59+
validations = {ApiArgValidator.PositiveNumber})
60+
private Long podId;
61+
62+
@Parameter(name = ApiConstants.GATEWAY,
63+
type = CommandType.STRING,
64+
required = true,
65+
description = "The gateway for the management network.",
66+
validations = {ApiArgValidator.NotNullOrEmpty})
67+
private String gateway;
68+
69+
@Parameter(name = ApiConstants.NETMASK,
70+
type = CommandType.STRING,
71+
required = true,
72+
description = "The netmask for the management network.",
73+
validations = {ApiArgValidator.NotNullOrEmpty})
74+
private String netmask;
75+
76+
@Parameter(name = ApiConstants.START_IP,
77+
type = CommandType.STRING,
78+
required = true,
79+
description = "The starting IP address.",
80+
validations = {ApiArgValidator.NotNullOrEmpty})
81+
private String startIp;
82+
83+
@Parameter(name = ApiConstants.END_IP,
84+
type = CommandType.STRING,
85+
description = "The ending IP address.")
86+
private String endIp;
87+
88+
/////////////////////////////////////////////////////
89+
/////////////////// Accessors ///////////////////////
90+
/////////////////////////////////////////////////////
91+
92+
public Long getPodId() {
93+
return podId;
94+
}
95+
96+
public String getGateWay() {
97+
return gateway;
98+
}
99+
100+
public String getNetmask() {
101+
return netmask;
102+
}
103+
104+
public String getStartIp() {
105+
return startIp;
106+
}
107+
108+
public String getEndIp() {
109+
return endIp;
110+
}
111+
112+
@Override
113+
public String getEventType() {
114+
return EventTypes.EVENT_MANAGEMENT_IP_RANGE_CREATE;
115+
}
116+
117+
@Override
118+
public String getEventDescription() {
119+
return "Creating management ip range from " + getStartIp() + " to " + getEndIp() + " and gateway=" + getGateWay() + ", netmask=" + getNetmask() + " of pod=" + getPodId();
120+
}
121+
122+
@Override
123+
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException,
124+
ResourceAllocationException {
125+
Pod result = _configService.createPodIpRange(this);
126+
if (result != null) {
127+
PodResponse response = _responseGenerator.createPodResponse(result, false);
128+
response.setResponseName(getCommandName());
129+
this.setResponseObject(response);
130+
} else {
131+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create Pod IP Range.");
132+
}
133+
}
134+
135+
@Override
136+
public String getCommandName() {
137+
return APINAME.toLowerCase() + BaseAsyncCmd.RESPONSE_SUFFIX;
138+
}
139+
140+
@Override
141+
public long getEntityOwnerId() {
142+
return Account.ACCOUNT_ID_SYSTEM;
143+
}
144+
145+
}
Lines changed: 129 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,129 @@
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+
package org.apache.cloudstack.api.command.admin.network;
18+
19+
import org.apache.log4j.Logger;
20+
21+
import org.apache.cloudstack.acl.RoleType;
22+
import org.apache.cloudstack.api.ApiArgValidator;
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.BaseAsyncCmd;
27+
import org.apache.cloudstack.api.Parameter;
28+
import org.apache.cloudstack.api.response.PodResponse;
29+
import org.apache.cloudstack.api.ServerApiException;
30+
import org.apache.cloudstack.api.response.SuccessResponse;
31+
32+
import com.cloud.event.EventTypes;
33+
import com.cloud.exception.ConcurrentOperationException;
34+
import com.cloud.exception.ResourceUnavailableException;
35+
import com.cloud.user.Account;
36+
37+
@APICommand(name = DeleteManagementNetworkIpRangeCmd.APINAME,
38+
description = "Deletes a management network IP range. This action is only allowed when no IPs in this range are allocated.",
39+
responseObject = SuccessResponse.class,
40+
since = "4.11.0.0",
41+
requestHasSensitiveInfo = false,
42+
responseHasSensitiveInfo = false,
43+
authorized = {RoleType.Admin})
44+
public class DeleteManagementNetworkIpRangeCmd extends BaseAsyncCmd {
45+
public static final Logger s_logger = Logger.getLogger(DeleteManagementNetworkIpRangeCmd.class);
46+
47+
public static final String APINAME = "deleteManagementNetworkIpRange";
48+
49+
/////////////////////////////////////////////////////
50+
//////////////// API parameters /////////////////////
51+
/////////////////////////////////////////////////////
52+
53+
@Parameter(name = ApiConstants.POD_ID,
54+
type = CommandType.UUID,
55+
entityType = PodResponse.class,
56+
required = true,
57+
description = "UUID of POD, where the IP range belongs to.",
58+
validations = ApiArgValidator.PositiveNumber)
59+
private Long podId;
60+
61+
@Parameter(name = ApiConstants.START_IP,
62+
type = CommandType.STRING,
63+
required = true,
64+
description = "The starting IP address.",
65+
validations = ApiArgValidator.NotNullOrEmpty)
66+
private String startIp;
67+
68+
@Parameter(name = ApiConstants.END_IP,
69+
type = CommandType.STRING,
70+
required = true,
71+
description = "The ending IP address.",
72+
validations = ApiArgValidator.NotNullOrEmpty)
73+
private String endIp;
74+
75+
/////////////////////////////////////////////////////
76+
/////////////////// Accessors ///////////////////////
77+
/////////////////////////////////////////////////////
78+
79+
public Long getPodId() {
80+
return podId;
81+
}
82+
83+
public String getStartIp() {
84+
return startIp;
85+
}
86+
87+
public String getEndIp() {
88+
return endIp;
89+
}
90+
91+
@Override
92+
public String getEventType() {
93+
return EventTypes.EVENT_MANAGEMENT_IP_RANGE_DELETE;
94+
}
95+
96+
@Override
97+
public String getEventDescription() {
98+
return "Deleting management ip range from " + getStartIp() + " to " + getEndIp() + " of Pod: " + getPodId();
99+
}
100+
101+
@Override
102+
public void execute() {
103+
try {
104+
_configService.deletePodIpRange(this);
105+
SuccessResponse response = new SuccessResponse(getCommandName());
106+
this.setResponseObject(response);
107+
} catch (ResourceUnavailableException ex) {
108+
s_logger.warn("Exception: ", ex);
109+
throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, ex.getMessage());
110+
} catch (ConcurrentOperationException ex) {
111+
s_logger.warn("Exception: ", ex);
112+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
113+
} catch (Exception e) {
114+
s_logger.warn("Failed to delete management ip range from " + getStartIp() + " to " + getEndIp() + " of Pod: " + getPodId(), e);
115+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
116+
}
117+
}
118+
119+
@Override
120+
public String getCommandName() {
121+
return APINAME.toLowerCase() + BaseAsyncCmd.RESPONSE_SUFFIX;
122+
}
123+
124+
@Override
125+
public long getEntityOwnerId() {
126+
return Account.ACCOUNT_ID_SYSTEM;
127+
}
128+
129+
}

api/src/org/apache/cloudstack/api/response/PodResponse.java

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -55,11 +55,11 @@ public class PodResponse extends BaseResponse {
5555

5656
@SerializedName("startip")
5757
@Param(description = "the starting IP for the Pod")
58-
private String startIp;
58+
private List<String> startIp;
5959

6060
@SerializedName("endip")
6161
@Param(description = "the ending IP for the Pod")
62-
private String endIp;
62+
private List<String> endIp;
6363

6464
@SerializedName("allocationstate")
6565
@Param(description = "the allocation state of the Pod")
@@ -117,19 +117,19 @@ public void setNetmask(String netmask) {
117117
this.netmask = netmask;
118118
}
119119

120-
public String getStartIp() {
120+
public List<String> getStartIp() {
121121
return startIp;
122122
}
123123

124-
public void setStartIp(String startIp) {
124+
public void setStartIp(List<String> startIp) {
125125
this.startIp = startIp;
126126
}
127127

128-
public String getEndIp() {
128+
public List<String> getEndIp() {
129129
return endIp;
130130
}
131131

132-
public void setEndIp(String endIp) {
132+
public void setEndIp(List<String> endIp) {
133133
this.endIp = endIp;
134134
}
135135

0 commit comments

Comments
 (0)