Skip to content

Commit d497656

Browse files
Sigert Goeminnefmaximus
authored andcommitted
CLOUDSTACK-10024: Network migration support
Co-Authored-By: Frank Maximus frank.maximus@nuagenetworks.net Co-Authored-By: Raf Smeets raf.smeets@nuagenetworks.net New API’s: * migrateNetwork * migrateVpc
1 parent 12f526b commit d497656

85 files changed

Lines changed: 5288 additions & 502 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/com/cloud/event/EventTypes.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,7 @@ public class EventTypes {
130130
public static final String EVENT_NETWORK_CREATE = "NETWORK.CREATE";
131131
public static final String EVENT_NETWORK_DELETE = "NETWORK.DELETE";
132132
public static final String EVENT_NETWORK_UPDATE = "NETWORK.UPDATE";
133+
public static final String EVENT_NETWORK_MIGRATE = "NETWORK.MIGRATE";
133134
public static final String EVENT_FIREWALL_OPEN = "FIREWALL.OPEN";
134135
public static final String EVENT_FIREWALL_CLOSE = "FIREWALL.CLOSE";
135136
public static final String EVENT_FIREWALL_UPDATE = "FIREWALL.UPDATE";

api/src/com/cloud/network/NetworkService.java

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
import com.cloud.exception.ResourceUnavailableException;
3737
import com.cloud.network.Network.Service;
3838
import com.cloud.network.Networks.TrafficType;
39+
import com.cloud.network.vpc.Vpc;
3940
import com.cloud.offering.NetworkOffering;
4041
import com.cloud.user.Account;
4142
import com.cloud.user.User;
@@ -82,6 +83,24 @@ IpAddress allocatePortableIP(Account ipOwner, int regionId, Long zoneId, Long ne
8283
Network updateGuestNetwork(long networkId, String name, String displayText, Account callerAccount, User callerUser, String domainSuffix, Long networkOfferingId,
8384
Boolean changeCidr, String guestVmCidr, Boolean displayNetwork, String newUUID, boolean updateInSequence, boolean forced);
8485

86+
/**
87+
* Migrate a network from one physical network to another physical network
88+
* @param networkId of the network that needs to be migrated
89+
* @param networkOfferingId new network offering id for the network
90+
* @param resume if previous migration failed try to resume of just fail directly because anomaly is detected
91+
* @return the migrated network
92+
*/
93+
Network migrateGuestNetwork(long networkId, long networkOfferingId, Account callerAccount, User callerUser, boolean resume);
94+
95+
/**
96+
* Migrate a vpc from on physical network to another physical network
97+
* @param vpcId the id of the vpc that needs to be migrated
98+
* @param vpcNetworkofferingId the new vpc offering id
99+
* @param resume if previous migration failed try to resume of just fail directly because anomaly is detected
100+
* @return the migrated vpc
101+
*/
102+
Vpc migrateVpcNetwork(long vpcId, long vpcNetworkofferingId, Map<String, String> networkToOffering, Account account, User callerUser, boolean resume);
103+
85104
PhysicalNetwork createPhysicalNetwork(Long zoneId, String vnetRange, String networkSpeed, List<String> isolationMethods, String broadcastDomainRange, Long domainId,
86105
List<String> tags, String name);
87106

api/src/com/cloud/network/Networks.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -246,6 +246,7 @@ public static String getValue(String uriString) throws URISyntaxException {
246246
* encode a string into a BroadcastUri
247247
* @param candidate the input string
248248
* @return an URI containing an appropriate (possibly given) scheme and the value
249+
*
249250
*/
250251
public static URI fromString(String candidate) {
251252
try {

api/src/com/cloud/offering/NetworkOffering.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ public enum State {
3838
}
3939

4040
public enum Detail {
41-
InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits
41+
InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, RelatedNetworkOffering
4242
}
4343

4444
public final static String SystemPublicNetwork = "System-Public-Network";

api/src/com/cloud/server/ResourceTag.java

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,9 @@ public enum ResourceObjectType {
5858
LBStickinessPolicy(false, true),
5959
LBHealthCheckPolicy(false, true),
6060
SnapshotPolicy(false, true),
61-
GuestOs(false, true);
61+
GuestOs(false, true),
62+
NetworkOffering(false, true),
63+
VpcOffering(true, false);
6264

6365

6466
ResourceObjectType(boolean resourceTagsSupport, boolean resourceMetadataSupport) {

api/src/com/cloud/vm/NicSecondaryIp.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@ public interface NicSecondaryIp extends ControlledEntity, Identity, InternalIden
3232

3333
long getNicId();
3434

35+
void setNicId(long nicId);
36+
3537
String getIp4Address();
3638

3739
String getIp6Address();

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,7 @@ public class ApiConstants {
332332
public static final String COUNT = "count";
333333
public static final String TRAFFIC_TYPE = "traffictype";
334334
public static final String NETWORK_OFFERING_ID = "networkofferingid";
335+
public static final String TIER_NETWORK_OFFERINGS = "tiernetworkofferings";
335336
public static final String NETWORK_IDS = "networkids";
336337
public static final String NETWORK_ID = "networkid";
337338
public static final String NIC_ID = "nicid";
@@ -375,6 +376,7 @@ public class ApiConstants {
375376
public static final String ZONE_TOKEN = "zonetoken";
376377
public static final String DHCP_PROVIDER = "dhcpprovider";
377378
public static final String RESULT = "success";
379+
public static final String RESUME = "resume";
378380
public static final String LUN_ID = "lunId";
379381
public static final String IQN = "iqn";
380382
public static final String AGGREGATE_NAME = "aggregatename";
Lines changed: 155 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,155 @@
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.SecurityChecker.AccessType;
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.BaseAsyncCmd;
27+
import org.apache.cloudstack.api.Parameter;
28+
import org.apache.cloudstack.api.ResponseObject.ResponseView;
29+
import org.apache.cloudstack.api.ServerApiException;
30+
import org.apache.cloudstack.api.response.NetworkOfferingResponse;
31+
import org.apache.cloudstack.api.response.NetworkResponse;
32+
import org.apache.cloudstack.context.CallContext;
33+
34+
import com.cloud.event.EventTypes;
35+
import com.cloud.exception.InvalidParameterValueException;
36+
import com.cloud.network.Network;
37+
import com.cloud.offering.NetworkOffering;
38+
import com.cloud.user.Account;
39+
import com.cloud.user.User;
40+
41+
@APICommand(name = "migrateNetwork", description = "moves a network to another physical network", responseObject = NetworkResponse.class, responseView = ResponseView.Restricted, entityType = {Network.class},
42+
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
43+
public class MigrateNetworkCmd extends BaseAsyncCmd {
44+
public static final Logger s_logger = Logger.getLogger(MigrateNetworkCmd.class.getName());
45+
46+
private static final String s_name = "migratenetworkresponse";
47+
48+
/////////////////////////////////////////////////////
49+
//////////////// API parameters /////////////////////
50+
/////////////////////////////////////////////////////
51+
@ACL(accessType = AccessType.OperateEntry)
52+
@Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType = NetworkResponse.class,
53+
required=true, description="the ID of the network")
54+
protected Long id;
55+
56+
@Parameter(name = ApiConstants.NETWORK_OFFERING_ID, type = CommandType.UUID, entityType = NetworkOfferingResponse.class, description = "network offering ID")
57+
private Long networkOfferingId;
58+
59+
@Parameter(name = ApiConstants.RESUME, type = CommandType.BOOLEAN, description = "true if previous network migration cmd failed")
60+
private Boolean resume;
61+
62+
/////////////////////////////////////////////////////
63+
/////////////////// Accessors ///////////////////////
64+
/////////////////////////////////////////////////////
65+
66+
public Long getId() {
67+
return id;
68+
}
69+
70+
public Long getNetworkOfferingId() {
71+
return networkOfferingId;
72+
}
73+
74+
public Boolean getResume() {
75+
return resume != null ? resume : false;
76+
}
77+
78+
/////////////////////////////////////////////////////
79+
/////////////// API Implementation///////////////////
80+
/////////////////////////////////////////////////////
81+
82+
@Override
83+
public String getCommandName() {
84+
return s_name;
85+
}
86+
87+
@Override
88+
public long getEntityOwnerId() {
89+
Network network = _networkService.getNetwork(id);
90+
if (network == null) {
91+
throw new InvalidParameterValueException("Networkd id=" + id + " doesn't exist");
92+
} else {
93+
return _networkService.getNetwork(id).getAccountId();
94+
}
95+
}
96+
97+
@Override
98+
public void execute() {
99+
User callerUser = _accountService.getActiveUser(CallContext.current().getCallingUserId());
100+
Account callerAccount = _accountService.getActiveAccountById(callerUser.getAccountId());
101+
Network network = _networkService.getNetwork(id);
102+
if (network == null) {
103+
throw new InvalidParameterValueException("Couldn't find network by id");
104+
}
105+
106+
Network result =
107+
_networkService.migrateGuestNetwork(getId(), getNetworkOfferingId(), callerAccount, callerUser, getResume());
108+
109+
if (result != null) {
110+
NetworkResponse response = _responseGenerator.createNetworkResponse(ResponseView.Restricted, result);
111+
response.setResponseName(getCommandName());
112+
setResponseObject(response);
113+
} else {
114+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update network");
115+
}
116+
}
117+
118+
@Override
119+
public String getEventDescription() {
120+
StringBuilder eventMsg = new StringBuilder("Migrating network: " + getId());
121+
if (getNetworkOfferingId() != null) {
122+
Network network = _networkService.getNetwork(getId());
123+
if (network == null) {
124+
throw new InvalidParameterValueException("Network id=" + id + " doesn't exist");
125+
}
126+
if (network.getNetworkOfferingId() != getNetworkOfferingId()) {
127+
NetworkOffering oldOff = _entityMgr.findById(NetworkOffering.class, network.getNetworkOfferingId());
128+
NetworkOffering newOff = _entityMgr.findById(NetworkOffering.class, getNetworkOfferingId());
129+
if (newOff == null) {
130+
throw new InvalidParameterValueException("Network offering id supplied is invalid");
131+
}
132+
133+
eventMsg.append(". Original network offering id: " + oldOff.getUuid() + ", new network offering id: " + newOff.getUuid());
134+
}
135+
}
136+
137+
return eventMsg.toString();
138+
}
139+
140+
@Override
141+
public String getEventType() {
142+
return EventTypes.EVENT_NETWORK_MIGRATE;
143+
}
144+
145+
@Override
146+
public String getSyncObjType() {
147+
return BaseAsyncCmd.networkSyncObject;
148+
}
149+
150+
@Override
151+
public Long getSyncObjId() {
152+
return id;
153+
}
154+
155+
}
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
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.cloudstack.acl.SecurityChecker;
20+
import org.apache.cloudstack.api.ACL;
21+
import org.apache.cloudstack.api.APICommand;
22+
import org.apache.cloudstack.api.ApiConstants;
23+
import org.apache.cloudstack.api.ApiErrorCode;
24+
import org.apache.cloudstack.api.BaseAsyncCmd;
25+
import org.apache.cloudstack.api.Parameter;
26+
import org.apache.cloudstack.api.ResponseObject;
27+
import org.apache.cloudstack.api.ServerApiException;
28+
import org.apache.cloudstack.api.response.VpcOfferingResponse;
29+
import org.apache.cloudstack.api.response.VpcResponse;
30+
import org.apache.cloudstack.context.CallContext;
31+
import org.apache.log4j.Logger;
32+
33+
import java.util.HashMap;
34+
import java.util.Map;
35+
36+
import com.cloud.event.EventTypes;
37+
import com.cloud.network.vpc.Vpc;
38+
import com.cloud.user.Account;
39+
import com.cloud.user.User;
40+
41+
@APICommand(name = "migrateVPC", description = "moves a vpc to another physical network", responseObject = VpcResponse.class, responseView = ResponseObject.ResponseView.Restricted, entityType = {Vpc.class},
42+
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
43+
public class MigrateVPCCmd extends BaseAsyncCmd {
44+
public static final Logger s_logger = Logger.getLogger(MigrateVPCCmd.class.getName());
45+
46+
private static final String s_name = "migratevpcresponse";
47+
48+
/////////////////////////////////////////////////////
49+
//////////////// API parameters /////////////////////
50+
/////////////////////////////////////////////////////
51+
@ACL(accessType = SecurityChecker.AccessType.OperateEntry)
52+
@Parameter(name= ApiConstants.VPC_ID, type=CommandType.UUID, entityType = VpcResponse.class,
53+
required=true, description = "the ID of the vpc")
54+
protected Long id;
55+
56+
@Parameter(name = ApiConstants.VPC_OFF_ID, type = CommandType.UUID, entityType = VpcOfferingResponse.class, required=true, description = "vpc offering ID")
57+
private Long vpcOfferingId;
58+
59+
@Parameter(name = ApiConstants.TIER_NETWORK_OFFERINGS, type = CommandType.MAP, description = "network offering ids for each network in the vpc. Example: tierNetworkOfferings[0].networkId=networkId1&tierNetworkOfferings[0].networkOfferingId=newNetworkofferingId1&tierNetworkOfferings[1].networkId=networkId2&tierNetworkOfferings[1].networkOfferingId=newNetworkofferingId2")
60+
private Map<Integer, HashMap<String, String>> tierNetworkOfferings;
61+
62+
@Parameter(name = ApiConstants.RESUME, type = CommandType.BOOLEAN, description = "true if previous network migration cmd failed")
63+
private Boolean resume;
64+
65+
/////////////////////////////////////////////////////
66+
/////////////////// Accessors ///////////////////////
67+
/////////////////////////////////////////////////////
68+
69+
public Long getId() {
70+
return id;
71+
}
72+
73+
public Long getVpcOfferingId() {
74+
return vpcOfferingId;
75+
}
76+
77+
public Boolean getResume() {
78+
return resume == null ? false : resume;
79+
}
80+
81+
public Map<String, String> getTierNetworkOfferings() {
82+
HashMap<String, String> flatMap = new HashMap<>();
83+
84+
if (tierNetworkOfferings == null) {
85+
return flatMap;
86+
}
87+
88+
for (HashMap<String, String> map : tierNetworkOfferings.values()) {
89+
flatMap.put(map.get("networkid"), map.get("networkofferingid"));
90+
}
91+
92+
return flatMap;
93+
}
94+
95+
/////////////////////////////////////////////////////
96+
/////////////// API Implementation///////////////////
97+
/////////////////////////////////////////////////////
98+
99+
@Override
100+
public String getCommandName() {
101+
return s_name;
102+
}
103+
104+
@Override
105+
public void execute() {
106+
User callerUser = _accountService.getActiveUser(CallContext.current().getCallingUserId());
107+
Account callerAccount = _accountService.getActiveAccountById(callerUser.getAccountId());
108+
109+
Vpc result =
110+
_networkService.migrateVpcNetwork(getId(), getVpcOfferingId(), getTierNetworkOfferings(), callerAccount, callerUser, getResume());
111+
112+
if (result != null) {
113+
VpcResponse response = _responseGenerator.createVpcResponse(ResponseObject.ResponseView.Restricted, result);
114+
response.setResponseName(getCommandName());
115+
setResponseObject(response);
116+
} else {
117+
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to migrate vpc");
118+
}
119+
}
120+
121+
@Override
122+
public String getEventDescription() { return "Migrating vpc: " + getId() + " to new vpc offering (" + vpcOfferingId + ")"; }
123+
124+
@Override
125+
public String getEventType() {
126+
return EventTypes.EVENT_NETWORK_MIGRATE;
127+
}
128+
129+
@Override
130+
public String getSyncObjType() {
131+
return BaseAsyncCmd.networkSyncObject;
132+
}
133+
134+
@Override
135+
public Long getSyncObjId() {
136+
return id;
137+
}
138+
139+
@Override
140+
public long getEntityOwnerId() {
141+
return CallContext.current().getCallingAccount().getId();
142+
}
143+
144+
}

0 commit comments

Comments
 (0)