Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

CLOUDSTACK-10024: Network migration support #2259

Merged
merged 1 commit into from Dec 21, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
1 change: 1 addition & 0 deletions api/src/com/cloud/event/EventTypes.java
Expand Up @@ -130,6 +130,7 @@ public class EventTypes {
public static final String EVENT_NETWORK_CREATE = "NETWORK.CREATE";
public static final String EVENT_NETWORK_DELETE = "NETWORK.DELETE";
public static final String EVENT_NETWORK_UPDATE = "NETWORK.UPDATE";
public static final String EVENT_NETWORK_MIGRATE = "NETWORK.MIGRATE";
public static final String EVENT_FIREWALL_OPEN = "FIREWALL.OPEN";
public static final String EVENT_FIREWALL_CLOSE = "FIREWALL.CLOSE";
public static final String EVENT_FIREWALL_UPDATE = "FIREWALL.UPDATE";
Expand Down
19 changes: 19 additions & 0 deletions api/src/com/cloud/network/NetworkService.java
Expand Up @@ -36,6 +36,7 @@
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.network.Network.Service;
import com.cloud.network.Networks.TrafficType;
import com.cloud.network.vpc.Vpc;
import com.cloud.offering.NetworkOffering;
import com.cloud.user.Account;
import com.cloud.user.User;
Expand Down Expand Up @@ -82,6 +83,24 @@ IpAddress allocatePortableIP(Account ipOwner, int regionId, Long zoneId, Long ne
Network updateGuestNetwork(long networkId, String name, String displayText, Account callerAccount, User callerUser, String domainSuffix, Long networkOfferingId,
Boolean changeCidr, String guestVmCidr, Boolean displayNetwork, String newUUID, boolean updateInSequence, boolean forced);

/**
* Migrate a network from one physical network to another physical network
* @param networkId of the network that needs to be migrated
* @param networkOfferingId new network offering id for the network
* @param resume if previous migration failed try to resume of just fail directly because anomaly is detected
* @return the migrated network
*/
Network migrateGuestNetwork(long networkId, long networkOfferingId, Account callerAccount, User callerUser, boolean resume);

/**
* Migrate a vpc from on physical network to another physical network
* @param vpcId the id of the vpc that needs to be migrated
* @param vpcNetworkofferingId the new vpc offering id
* @param resume if previous migration failed try to resume of just fail directly because anomaly is detected
* @return the migrated vpc
*/
Vpc migrateVpcNetwork(long vpcId, long vpcNetworkofferingId, Map<String, String> networkToOffering, Account account, User callerUser, boolean resume);

PhysicalNetwork createPhysicalNetwork(Long zoneId, String vnetRange, String networkSpeed, List<String> isolationMethods, String broadcastDomainRange, Long domainId,
List<String> tags, String name);

Expand Down
1 change: 1 addition & 0 deletions api/src/com/cloud/network/Networks.java
Expand Up @@ -246,6 +246,7 @@ public static String getValue(String uriString) throws URISyntaxException {
* encode a string into a BroadcastUri
* @param candidate the input string
* @return an URI containing an appropriate (possibly given) scheme and the value
*
*/
public static URI fromString(String candidate) {
try {
Expand Down
2 changes: 1 addition & 1 deletion api/src/com/cloud/offering/NetworkOffering.java
Expand Up @@ -38,7 +38,7 @@ public enum State {
}

public enum Detail {
InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits
InternalLbProvider, PublicLbProvider, servicepackageuuid, servicepackagedescription, PromiscuousMode, MacAddressChanges, ForgedTransmits, RelatedNetworkOffering
}

public final static String SystemPublicNetwork = "System-Public-Network";
Expand Down
4 changes: 3 additions & 1 deletion api/src/com/cloud/server/ResourceTag.java
Expand Up @@ -58,7 +58,9 @@ public enum ResourceObjectType {
LBStickinessPolicy(false, true),
LBHealthCheckPolicy(false, true),
SnapshotPolicy(false, true),
GuestOs(false, true);
GuestOs(false, true),
NetworkOffering(false, true),
VpcOffering(true, false);


ResourceObjectType(boolean resourceTagsSupport, boolean resourceMetadataSupport) {
Expand Down
2 changes: 2 additions & 0 deletions api/src/com/cloud/vm/NicSecondaryIp.java
Expand Up @@ -32,6 +32,8 @@ public interface NicSecondaryIp extends ControlledEntity, Identity, InternalIden

long getNicId();

void setNicId(long nicId);

String getIp4Address();

String getIp6Address();
Expand Down
2 changes: 2 additions & 0 deletions api/src/org/apache/cloudstack/api/ApiConstants.java
Expand Up @@ -332,6 +332,7 @@ public class ApiConstants {
public static final String COUNT = "count";
public static final String TRAFFIC_TYPE = "traffictype";
public static final String NETWORK_OFFERING_ID = "networkofferingid";
public static final String TIER_NETWORK_OFFERINGS = "tiernetworkofferings";
public static final String NETWORK_IDS = "networkids";
public static final String NETWORK_ID = "networkid";
public static final String NIC_ID = "nicid";
Expand Down Expand Up @@ -375,6 +376,7 @@ public class ApiConstants {
public static final String ZONE_TOKEN = "zonetoken";
public static final String DHCP_PROVIDER = "dhcpprovider";
public static final String RESULT = "success";
public static final String RESUME = "resume";
public static final String LUN_ID = "lunId";
public static final String IQN = "iqn";
public static final String AGGREGATE_NAME = "aggregatename";
Expand Down
@@ -0,0 +1,155 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command.admin.network;

import org.apache.log4j.Logger;

import org.apache.cloudstack.acl.SecurityChecker.AccessType;
import org.apache.cloudstack.api.ACL;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ResponseObject.ResponseView;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.NetworkOfferingResponse;
import org.apache.cloudstack.api.response.NetworkResponse;
import org.apache.cloudstack.context.CallContext;

import com.cloud.event.EventTypes;
import com.cloud.exception.InvalidParameterValueException;
import com.cloud.network.Network;
import com.cloud.offering.NetworkOffering;
import com.cloud.user.Account;
import com.cloud.user.User;

@APICommand(name = "migrateNetwork", description = "moves a network to another physical network", responseObject = NetworkResponse.class, responseView = ResponseView.Restricted, entityType = {Network.class},
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no default authorized defined, please fix.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API does no define a since as well.

public class MigrateNetworkCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(MigrateNetworkCmd.class.getName());

private static final String s_name = "migratenetworkresponse";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please follow recent API implementation patterns, see RoleCmd as an example. The API name and response names can be refactored.


/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@ACL(accessType = AccessType.OperateEntry)
@Parameter(name=ApiConstants.NETWORK_ID, type=CommandType.UUID, entityType = NetworkResponse.class,
required=true, description="the ID of the network")
protected Long id;

@Parameter(name = ApiConstants.NETWORK_OFFERING_ID, type = CommandType.UUID, entityType = NetworkOfferingResponse.class, description = "network offering ID")
private Long networkOfferingId;

@Parameter(name = ApiConstants.RESUME, type = CommandType.BOOLEAN, description = "true if previous network migration cmd failed")
private Boolean resume;

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////

public Long getId() {
return id;
}

public Long getNetworkOfferingId() {
return networkOfferingId;
}

public Boolean getResume() {
return resume != null ? resume : false;
}

/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

@Override
public String getCommandName() {
return s_name;
}

@Override
public long getEntityOwnerId() {
Network network = _networkService.getNetwork(id);
if (network == null) {
throw new InvalidParameterValueException("Networkd id=" + id + " doesn't exist");
} else {
return _networkService.getNetwork(id).getAccountId();
}
}

@Override
public void execute() {
User callerUser = _accountService.getActiveUser(CallContext.current().getCallingUserId());
Account callerAccount = _accountService.getActiveAccountById(callerUser.getAccountId());
Network network = _networkService.getNetwork(id);
if (network == null) {
throw new InvalidParameterValueException("Couldn't find network by id");
}

Network result =
_networkService.migrateGuestNetwork(getId(), getNetworkOfferingId(), callerAccount, callerUser, getResume());

if (result != null) {
NetworkResponse response = _responseGenerator.createNetworkResponse(ResponseView.Restricted, result);
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to update network");
}
}

@Override
public String getEventDescription() {
StringBuilder eventMsg = new StringBuilder("Migrating network: " + getId());
if (getNetworkOfferingId() != null) {
Network network = _networkService.getNetwork(getId());
if (network == null) {
throw new InvalidParameterValueException("Network id=" + id + " doesn't exist");
}
if (network.getNetworkOfferingId() != getNetworkOfferingId()) {
NetworkOffering oldOff = _entityMgr.findById(NetworkOffering.class, network.getNetworkOfferingId());
NetworkOffering newOff = _entityMgr.findById(NetworkOffering.class, getNetworkOfferingId());
if (newOff == null) {
throw new InvalidParameterValueException("Network offering id supplied is invalid");
}

eventMsg.append(". Original network offering id: " + oldOff.getUuid() + ", new network offering id: " + newOff.getUuid());
}
}

return eventMsg.toString();
}

@Override
public String getEventType() {
return EventTypes.EVENT_NETWORK_MIGRATE;
}

@Override
public String getSyncObjType() {
return BaseAsyncCmd.networkSyncObject;
}

@Override
public Long getSyncObjId() {
return id;
}

}
@@ -0,0 +1,144 @@
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
package org.apache.cloudstack.api.command.admin.network;

import org.apache.cloudstack.acl.SecurityChecker;
import org.apache.cloudstack.api.ACL;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.ApiErrorCode;
import org.apache.cloudstack.api.BaseAsyncCmd;
import org.apache.cloudstack.api.Parameter;
import org.apache.cloudstack.api.ResponseObject;
import org.apache.cloudstack.api.ServerApiException;
import org.apache.cloudstack.api.response.VpcOfferingResponse;
import org.apache.cloudstack.api.response.VpcResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.log4j.Logger;

import java.util.HashMap;
import java.util.Map;

import com.cloud.event.EventTypes;
import com.cloud.network.vpc.Vpc;
import com.cloud.user.Account;
import com.cloud.user.User;

@APICommand(name = "migrateVPC", description = "moves a vpc to another physical network", responseObject = VpcResponse.class, responseView = ResponseObject.ResponseView.Restricted, entityType = {Vpc.class},
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is no default authorized defined, please fix.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The API does no define a since as well.

public class MigrateVPCCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(MigrateVPCCmd.class.getName());

private static final String s_name = "migratevpcresponse";
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same as above, refactor to use APINAME etc patterns as used in recent APIs.


/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////
@ACL(accessType = SecurityChecker.AccessType.OperateEntry)
@Parameter(name= ApiConstants.VPC_ID, type=CommandType.UUID, entityType = VpcResponse.class,
required=true, description = "the ID of the vpc")
protected Long id;

@Parameter(name = ApiConstants.VPC_OFF_ID, type = CommandType.UUID, entityType = VpcOfferingResponse.class, required=true, description = "vpc offering ID")
private Long vpcOfferingId;

@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")
private Map<Integer, HashMap<String, String>> tierNetworkOfferings;

@Parameter(name = ApiConstants.RESUME, type = CommandType.BOOLEAN, description = "true if previous network migration cmd failed")
private Boolean resume;

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////

public Long getId() {
return id;
}

public Long getVpcOfferingId() {
return vpcOfferingId;
}

public Boolean getResume() {
return resume == null ? false : resume;
}

public Map<String, String> getTierNetworkOfferings() {
HashMap<String, String> flatMap = new HashMap<>();

if (tierNetworkOfferings == null) {
return flatMap;
}

for (HashMap<String, String> map : tierNetworkOfferings.values()) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a putall could be used here.

flatMap.put(map.get("networkid"), map.get("networkofferingid"));
}

return flatMap;
}

/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////

@Override
public String getCommandName() {
return s_name;
}

@Override
public void execute() {
User callerUser = _accountService.getActiveUser(CallContext.current().getCallingUserId());
Account callerAccount = _accountService.getActiveAccountById(callerUser.getAccountId());

Vpc result =
_networkService.migrateVpcNetwork(getId(), getVpcOfferingId(), getTierNetworkOfferings(), callerAccount, callerUser, getResume());

if (result != null) {
VpcResponse response = _responseGenerator.createVpcResponse(ResponseObject.ResponseView.Restricted, result);
response.setResponseName(getCommandName());
setResponseObject(response);
} else {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to migrate vpc");
}
}

@Override
public String getEventDescription() { return "Migrating vpc: " + getId() + " to new vpc offering (" + vpcOfferingId + ")"; }

@Override
public String getEventType() {
return EventTypes.EVENT_NETWORK_MIGRATE;
}

@Override
public String getSyncObjType() {
return BaseAsyncCmd.networkSyncObject;
}

@Override
public Long getSyncObjId() {
return id;
}

@Override
public long getEntityOwnerId() {
return CallContext.current().getCallingAccount().getId();
}

}