Skip to content

Commit 747608f

Browse files
weizhouapachekioiekioieDaanHoogland
authored
Add New API endpoint: UpdateVlanIpRange (#5411)
* Added Logic to update the user_ip_address table * Edited ConfigurationManagerImpl * Refactor UpdateVlanIpRangeCmd location * Checkstyle corrections * Mock updateVlanAndPublicIpRange * Changes: - UpdateVlanIpRangeCmd - changed since to 4.15.0 - ConfigurationService - Updated Javadoc - ConfigurationManager - Updated Javadoc - Added Unit tests - Added license - Update server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java - fix some bugs in #5411 and add support for ipv6 and forsystemvms - fix #5411: disallow forsystemvms if ip range is dedicated - update #5411: ui changes - update #5411: support gateway/netmask change - update #5411: change to sync call and fix bugs Co-authored-by: kioie <kioieddy@google.com> Co-authored-by: kioie <kioi@outlook.com> Co-authored-by: dahn <daan.hoogland@gmail.com>
1 parent 3b4523f commit 747608f

15 files changed

Lines changed: 771 additions & 29 deletions

File tree

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

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@
3939
import org.apache.cloudstack.api.command.admin.vlan.DedicatePublicIpRangeCmd;
4040
import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd;
4141
import org.apache.cloudstack.api.command.admin.vlan.ReleasePublicIpRangeCmd;
42+
import org.apache.cloudstack.api.command.admin.vlan.UpdateVlanIpRangeCmd;
4243
import org.apache.cloudstack.api.command.admin.zone.CreateZoneCmd;
4344
import org.apache.cloudstack.api.command.admin.zone.DeleteZoneCmd;
4445
import org.apache.cloudstack.api.command.admin.zone.UpdateZoneCmd;
@@ -272,6 +273,12 @@ public interface ConfigurationService {
272273
Vlan createVlanAndPublicIpRange(CreateVlanIpRangeCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException,
273274
ResourceAllocationException;
274275

276+
/**
277+
* Updates the IP address Range for the VLAN on the database
278+
* @return The Updated Vlan Object
279+
*/
280+
Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws ConcurrentOperationException,
281+
ResourceUnavailableException, ResourceAllocationException;
275282
/**
276283
* Marks the the account with the default zone-id.
277284
*

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,7 @@ public class EventTypes {
324324
public static final String EVENT_VLAN_IP_RANGE_DELETE = "VLAN.IP.RANGE.DELETE";
325325
public static final String EVENT_VLAN_IP_RANGE_DEDICATE = "VLAN.IP.RANGE.DEDICATE";
326326
public static final String EVENT_VLAN_IP_RANGE_RELEASE = "VLAN.IP.RANGE.RELEASE";
327+
public static final String EVENT_VLAN_IP_RANGE_UPDATE = "VLAN.IP.RANGE.UPDATE";
327328

328329
public static final String EVENT_MANAGEMENT_IP_RANGE_CREATE = "MANAGEMENT.IP.RANGE.CREATE";
329330
public static final String EVENT_MANAGEMENT_IP_RANGE_DELETE = "MANAGEMENT.IP.RANGE.DELETE";
Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
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.vlan;
18+
19+
import org.apache.cloudstack.acl.RoleType;
20+
import org.apache.cloudstack.api.APICommand;
21+
import org.apache.cloudstack.api.ApiConstants;
22+
import org.apache.cloudstack.api.ApiErrorCode;
23+
import org.apache.cloudstack.api.BaseCmd;
24+
import org.apache.cloudstack.api.Parameter;
25+
import org.apache.cloudstack.api.ServerApiException;
26+
import org.apache.cloudstack.api.response.VlanIpRangeResponse;
27+
import org.apache.log4j.Logger;
28+
29+
import com.cloud.dc.Vlan;
30+
import com.cloud.exception.ConcurrentOperationException;
31+
import com.cloud.exception.ResourceAllocationException;
32+
import com.cloud.exception.ResourceUnavailableException;
33+
import com.cloud.user.Account;
34+
import com.cloud.utils.net.NetUtils;
35+
36+
@APICommand(name = UpdateVlanIpRangeCmd.APINAME, description = "Updates a VLAN IP range.", responseObject =
37+
VlanIpRangeResponse.class, since = "4.16.0",
38+
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false,
39+
authorized = {RoleType.Admin})
40+
public class UpdateVlanIpRangeCmd extends BaseCmd {
41+
42+
public static final String APINAME = "updateVlanIpRange";
43+
public static final Logger s_logger = Logger.getLogger(UpdateVlanIpRangeCmd.class.getName());
44+
45+
/////////////////////////////////////////////////////
46+
//////////////// API parameters /////////////////////
47+
/////////////////////////////////////////////////////
48+
49+
50+
@Parameter(name = ApiConstants.ID, type = CommandType.UUID, entityType = VlanIpRangeResponse.class, required = true,
51+
description = "the UUID of the VLAN IP range")
52+
private Long id;
53+
54+
@Parameter(name = ApiConstants.GATEWAY, type = CommandType.STRING, description = "the gateway of the VLAN IP range")
55+
private String gateway;
56+
57+
@Parameter(name = ApiConstants.NETMASK, type = CommandType.STRING, description = "the netmask of the VLAN IP range")
58+
private String netmask;
59+
60+
@Parameter(name = ApiConstants.START_IP, type = CommandType.STRING, description = "the beginning IP address in the VLAN IP range")
61+
private String startIp;
62+
63+
@Parameter(name = ApiConstants.END_IP, type = CommandType.STRING,
64+
description = "the ending IP address in the VLAN IP range")
65+
private String endIp;
66+
67+
@Parameter(name = ApiConstants.START_IPV6, type = CommandType.STRING, description = "the beginning IPv6 address in the IPv6 network range")
68+
private String startIpv6;
69+
70+
@Parameter(name = ApiConstants.END_IPV6, type = CommandType.STRING, description = "the ending IPv6 address in the IPv6 network range")
71+
private String endIpv6;
72+
73+
@Parameter(name = ApiConstants.IP6_GATEWAY, type = CommandType.STRING, description = "the gateway of the IPv6 network")
74+
private String ip6Gateway;
75+
76+
@Parameter(name = ApiConstants.IP6_CIDR, type = CommandType.STRING, description = "the CIDR of IPv6 network, must be at least /64")
77+
private String ip6Cidr;
78+
79+
@Parameter(name = ApiConstants.FOR_SYSTEM_VMS, type = CommandType.BOOLEAN, description = "true if IP range is set to system vms, false if not")
80+
private Boolean forSystemVms;
81+
82+
/////////////////////////////////////////////////////
83+
/////////////////// Accessors ///////////////////////
84+
/////////////////////////////////////////////////////
85+
public Long getId() {
86+
return id;
87+
}
88+
89+
public String getGateway() {
90+
return gateway;
91+
}
92+
93+
public String getEndIp() {
94+
return endIp;
95+
}
96+
97+
public String getNetmask() {
98+
return netmask;
99+
}
100+
101+
public String getStartIp() {
102+
return startIp;
103+
}
104+
105+
public String getStartIpv6() {
106+
if (startIpv6 == null) {
107+
return null;
108+
}
109+
return NetUtils.standardizeIp6Address(startIpv6);
110+
}
111+
112+
public String getEndIpv6() {
113+
if (endIpv6 == null) {
114+
return null;
115+
}
116+
return NetUtils.standardizeIp6Address(endIpv6);
117+
}
118+
119+
public String getIp6Gateway() {
120+
if (ip6Gateway == null) {
121+
return null;
122+
}
123+
return NetUtils.standardizeIp6Address(ip6Gateway);
124+
}
125+
126+
public String getIp6Cidr() {
127+
if (ip6Cidr == null) {
128+
return null;
129+
}
130+
return NetUtils.standardizeIp6Cidr(ip6Cidr);
131+
}
132+
133+
public Boolean isForSystemVms() {
134+
return forSystemVms;
135+
}
136+
137+
/////////////////////////////////////////////////////
138+
/////////////// API Implementation///////////////////
139+
/////////////////////////////////////////////////////
140+
141+
@Override
142+
public void execute() throws ResourceUnavailableException, ResourceAllocationException {
143+
try {
144+
Vlan result = _configService.updateVlanAndPublicIpRange(this);
145+
if (result != null) {
146+
VlanIpRangeResponse response = _responseGenerator.createVlanIpRangeResponse(result);
147+
response.setResponseName(getCommandName());
148+
this.setResponseObject(response);
149+
} else {
150+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to Update vlan ip range");
151+
}
152+
} catch (ConcurrentOperationException ex) {
153+
s_logger.warn("Exception: ", ex);
154+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, ex.getMessage());
155+
}
156+
}
157+
158+
@Override
159+
public String getCommandName() {
160+
return APINAME.toLowerCase() + BaseCmd.RESPONSE_SUFFIX;
161+
}
162+
163+
@Override
164+
public long getEntityOwnerId() {
165+
return Account.ACCOUNT_ID_SYSTEM;
166+
}
167+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
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.vlan;
18+
19+
import junit.framework.TestCase;
20+
21+
import org.apache.cloudstack.api.ResponseGenerator;
22+
import org.apache.cloudstack.api.ServerApiException;
23+
import org.apache.cloudstack.api.response.VlanIpRangeResponse;
24+
import org.junit.Test;
25+
import org.mockito.Mockito;
26+
27+
import com.cloud.configuration.ConfigurationService;
28+
import com.cloud.dc.Vlan;
29+
import com.cloud.exception.ResourceAllocationException;
30+
import com.cloud.exception.ResourceUnavailableException;
31+
32+
public class UpdateVlanIpRangeCmdTest extends TestCase {
33+
34+
private UpdateVlanIpRangeCmd updateVlanIpRangeCmd;
35+
private ResponseGenerator responseGenerator;
36+
37+
@Test
38+
public void testUpdateSuccess() throws Exception {
39+
40+
ConfigurationService configService = Mockito.mock(ConfigurationService.class);
41+
Vlan result = Mockito.mock(Vlan.class);
42+
43+
responseGenerator = Mockito.mock(ResponseGenerator.class);
44+
updateVlanIpRangeCmd = new UpdateVlanIpRangeCmd();
45+
46+
Mockito.when(configService.updateVlanAndPublicIpRange(updateVlanIpRangeCmd)).thenReturn(result);
47+
updateVlanIpRangeCmd._configService = configService;
48+
49+
VlanIpRangeResponse ipRes = Mockito.mock(VlanIpRangeResponse.class);
50+
Mockito.when(responseGenerator.createVlanIpRangeResponse(result)).thenReturn(ipRes);
51+
52+
updateVlanIpRangeCmd._responseGenerator = responseGenerator;
53+
try {
54+
updateVlanIpRangeCmd.execute();
55+
} catch (ServerApiException ex) {
56+
assertEquals("Failed to Update vlan ip range", ex.getMessage());
57+
}
58+
}
59+
60+
@Test
61+
public void testUpdateFailure() throws ResourceAllocationException, ResourceUnavailableException {
62+
63+
ConfigurationService configService = Mockito.mock(ConfigurationService.class);
64+
65+
responseGenerator = Mockito.mock(ResponseGenerator.class);
66+
updateVlanIpRangeCmd = new UpdateVlanIpRangeCmd();
67+
updateVlanIpRangeCmd._configService = configService;
68+
69+
Mockito.when(configService.updateVlanAndPublicIpRange(updateVlanIpRangeCmd)).thenReturn(null);
70+
71+
try {
72+
updateVlanIpRangeCmd.execute();
73+
} catch (ServerApiException ex) {
74+
assertEquals("Failed to Update vlan ip range", ex.getMessage());
75+
}
76+
77+
}
78+
}

engine/schema/src/main/java/com/cloud/dc/VlanVO.java

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -118,11 +118,19 @@ public String getVlanGateway() {
118118
return vlanGateway;
119119
}
120120

121+
public void setVlanGateway(String vlanGateway) {
122+
this.vlanGateway = vlanGateway;
123+
}
124+
121125
@Override
122126
public String getVlanNetmask() {
123127
return vlanNetmask;
124128
}
125129

130+
public void setVlanNetmask(String vlanNetmask) {
131+
this.vlanNetmask = vlanNetmask;
132+
}
133+
126134
@Override
127135
public long getDataCenterId() {
128136
return dataCenterId;
@@ -234,6 +242,6 @@ public void setIp6Range(String ip6Range) {
234242
}
235243

236244
public void setIpRange(String ipRange) {
237-
this.ip6Range = ipRange;
245+
this.ipRange = ipRange;
238246
}
239247
}

engine/schema/src/main/java/com/cloud/network/dao/IPAddressDao.java

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

2121
import com.cloud.dc.Vlan.VlanType;
22+
import com.cloud.network.IpAddress.State;
2223
import com.cloud.utils.db.GenericDao;
2324
import com.cloud.utils.net.Ip;
2425

@@ -32,6 +33,8 @@ public interface IPAddressDao extends GenericDao<IPAddressVO, Long> {
3233

3334
List<IPAddressVO> listByVlanId(long vlanId);
3435

36+
List<IPAddressVO> listByVlanIdAndState(long vlanId, State state);
37+
3538
List<IPAddressVO> listByDcIdIpAddress(long dcId, String ipAddress);
3639

3740
List<IPAddressVO> listByDcId(long dcId);

engine/schema/src/main/java/com/cloud/network/dao/IPAddressDaoImpl.java

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,7 @@ public void init() {
7878
AllFieldsSearch.and("dataCenterId", AllFieldsSearch.entity().getDataCenterId(), Op.EQ);
7979
AllFieldsSearch.and("ipAddress", AllFieldsSearch.entity().getAddress(), Op.EQ);
8080
AllFieldsSearch.and("vlan", AllFieldsSearch.entity().getVlanId(), Op.EQ);
81+
AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), Op.EQ);
8182
AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAllocatedToAccountId(), Op.EQ);
8283
AllFieldsSearch.and("sourceNat", AllFieldsSearch.entity().isSourceNat(), Op.EQ);
8384
AllFieldsSearch.and("network", AllFieldsSearch.entity().getAssociatedWithNetworkId(), Op.EQ);
@@ -471,4 +472,12 @@ public void lockRange(long vlandbId) {
471472
sc.setParameters("vlan", vlandbId);
472473
lockRows(sc, null, true);
473474
}
475+
476+
@Override
477+
public List<IPAddressVO> listByVlanIdAndState(long vlanId, State state) {
478+
SearchCriteria<IPAddressVO> sc = AllFieldsSearch.create();
479+
sc.setParameters("vlan", vlanId);
480+
sc.setParameters("state", state);
481+
return listBy(sc);
482+
}
474483
}

engine/schema/src/main/java/com/cloud/network/dao/UserIpv6AddressDao.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
import java.util.List;
2020

21+
import com.cloud.network.IpAddress;
2122
import com.cloud.network.UserIpv6AddressVO;
2223
import com.cloud.utils.db.GenericDao;
2324

@@ -26,6 +27,8 @@ public interface UserIpv6AddressDao extends GenericDao<UserIpv6AddressVO, Long>
2627

2728
List<UserIpv6AddressVO> listByVlanId(long vlanId);
2829

30+
List<UserIpv6AddressVO> listByVlanIdAndState(long vlanId, IpAddress.State state);
31+
2932
List<UserIpv6AddressVO> listByDcId(long dcId);
3033

3134
List<UserIpv6AddressVO> listByNetwork(long networkId);

engine/schema/src/main/java/com/cloud/network/dao/UserIpv6AddressDaoImpl.java

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

2121

22+
import com.cloud.network.IpAddress;
2223
import org.apache.log4j.Logger;
2324
import org.springframework.stereotype.Component;
2425

@@ -43,6 +44,7 @@ public UserIpv6AddressDaoImpl() {
4344
AllFieldsSearch.and("dataCenterId", AllFieldsSearch.entity().getDataCenterId(), Op.EQ);
4445
AllFieldsSearch.and("ipAddress", AllFieldsSearch.entity().getAddress(), Op.EQ);
4546
AllFieldsSearch.and("vlan", AllFieldsSearch.entity().getVlanId(), Op.EQ);
47+
AllFieldsSearch.and("state", AllFieldsSearch.entity().getState(), Op.EQ);
4648
AllFieldsSearch.and("accountId", AllFieldsSearch.entity().getAccountId(), Op.EQ);
4749
AllFieldsSearch.and("network", AllFieldsSearch.entity().getNetworkId(), Op.EQ);
4850
AllFieldsSearch.and("physicalNetworkId", AllFieldsSearch.entity().getPhysicalNetworkId(), Op.EQ);
@@ -69,6 +71,14 @@ public List<UserIpv6AddressVO> listByVlanId(long vlanId) {
6971
return listBy(sc);
7072
}
7173

74+
@Override
75+
public List<UserIpv6AddressVO> listByVlanIdAndState(long vlanId, IpAddress.State state) {
76+
SearchCriteria<UserIpv6AddressVO> sc = AllFieldsSearch.create();
77+
sc.setParameters("vlan", vlanId);
78+
sc.setParameters("state", state);
79+
return listBy(sc);
80+
}
81+
7282
@Override
7383
public List<UserIpv6AddressVO> listByDcId(long dcId) {
7484
SearchCriteria<UserIpv6AddressVO> sc = AllFieldsSearch.create();

0 commit comments

Comments
 (0)