Skip to content

Commit

Permalink
CLOUDSTACK-10024: Network migration support
Browse files Browse the repository at this point in the history
Co-Authored-By: Frank Maximus frank.maximus@nuagenetworks.net
Co-Authored-By: Raf Smeets raf.smeets@nuagenetworks.

New API’s:
* migrateNetwork
* migrateVpc
  • Loading branch information
Sigert Goeminne committed Sep 26, 2017
1 parent a4036f7 commit 20088e9
Show file tree
Hide file tree
Showing 39 changed files with 3,258 additions and 172 deletions.
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
21 changes: 21 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,26 @@ 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
* @param networkOfferingId
* @param callerAccount
* @param callerUser
* @return
*/
Network migrateGuestNetwork(long networkId, Long networkOfferingId, Account callerAccount, User callerUser);

/**
* Migrate a vpc from on physical network to another physical network
* @param vpcId
* @param vpcNetworkofferingId
* @param account
* @param callerUser
* @return
*/
Vpc migrateVpcNetwork(long vpcId, long vpcNetworkofferingId, Map<String, String> networkToOffering, Account account, User callerUser);

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 @@ -242,6 +242,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
1 change: 1 addition & 0 deletions api/src/org/apache/cloudstack/api/ApiConstants.java
Expand Up @@ -317,6 +317,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
@@ -0,0 +1,150 @@
// 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.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
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 do another physical network", responseObject = NetworkResponse.class, responseView = ResponseView.Restricted, entityType = {Network.class},
requestHasSensitiveInfo = false, responseHasSensitiveInfo = false)
public class MigrateNetworkCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(MigrateNetworkCmd.class.getName());

private static final String s_name = "migratenetworkresponse";

/////////////////////////////////////////////////////
//////////////// 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;

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

public Long getId() {
return id;
}

public Long getNetworkOfferingId() {
return networkOfferingId;
}

/////////////////////////////////////////////////////
/////////////// 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() throws InsufficientCapacityException, ConcurrentOperationException {
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);

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,139 @@
// 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.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
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)
public class MigrateVPCCmd extends BaseAsyncCmd {
public static final Logger s_logger = Logger.getLogger(MigrateVPCCmd.class.getName());

private static final String s_name = "migratevpcresponse";

/////////////////////////////////////////////////////
//////////////// 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;

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

public Long getId() {
return id;
}

public Long getVpcOfferingId() {
return vpcOfferingId;
}

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

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

for (HashMap<String, String> map : tierNetworkOfferings.values()) {
flatMap.put(map.get("networkid"), map.get("networkofferingid"));
}

return flatMap;
}

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

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

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

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

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();
}

}
Expand Up @@ -69,6 +69,9 @@ public class UpdateNetworkOfferingCmd extends BaseCmd {
description = "maximum number of concurrent connections supported by the network offering")
private Integer maxConnections;

@Parameter(name = ApiConstants.TAGS, type = CommandType.STRING, description = "the tags for the network offering.", length = 4096)
private String tags;

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
Expand Down Expand Up @@ -105,6 +108,10 @@ public Boolean getKeepAliveEnabled() {
return keepAliveEnabled;
}

public String getTags() {
return tags;
}

/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
Expand Down
26 changes: 26 additions & 0 deletions core/src/com/cloud/agent/api/ReplugNicAnswer.java
@@ -0,0 +1,26 @@
///
// Copyright (c) 2016 Nokia
//
// Licensed 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 com.cloud.agent.api;

public class ReplugNicAnswer extends Answer {
public ReplugNicAnswer() {
}

public ReplugNicAnswer(ReplugNicCommand cmd, boolean success, String result) {
super(cmd, success, result);
}
}

0 comments on commit 20088e9

Please sign in to comment.