Skip to content

extensions: framework changes #121

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

Open
wants to merge 2 commits into
base: ExternalDeploymentIntegration
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ public class ApiConstants {
public static final String POST_URL = "postURL";
public static final String POWER_STATE = "powerstate";
public static final String PRECEDENCE = "precedence";
public static final String PREPARE_VM = "preparevm";
public static final String PRIVATE_INTERFACE = "privateinterface";
public static final String PRIVATE_IP = "privateip";
public static final String PRIVATE_PORT = "privateport";
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,17 +20,21 @@

import java.util.Map;

import com.cloud.agent.api.to.VirtualMachineTO;

public class PrepareExternalProvisioningAnswer extends Answer {

Map<String, String> serverDetails;
VirtualMachineTO virtualMachineTO;

public PrepareExternalProvisioningAnswer() {
super();
}

public PrepareExternalProvisioningAnswer(PrepareExternalProvisioningCommand cmd, Map<String, String> serverDetails, String details) {
public PrepareExternalProvisioningAnswer(PrepareExternalProvisioningCommand cmd, Map<String, String> externalDetails, VirtualMachineTO virtualMachineTO, String details) {
super(cmd, true, details);
this.serverDetails = serverDetails;
this.serverDetails = externalDetails;
this.virtualMachineTO = virtualMachineTO;
}

public PrepareExternalProvisioningAnswer(PrepareExternalProvisioningCommand cmd, boolean success, String details) {
Expand All @@ -40,4 +44,8 @@ public PrepareExternalProvisioningAnswer(PrepareExternalProvisioningCommand cmd,
public Map<String, String> getServerDetails() {
return serverDetails;
}

public VirtualMachineTO getVirtualMachineTO() {
return virtualMachineTO;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,19 +28,14 @@ public class PrepareExternalProvisioningCommand extends Command {
Long clusterId;
Map<String, Object> externalDetails;

public PrepareExternalProvisioningCommand(VirtualMachineTO vmUUID, Long clusterId) {
this.virtualMachineTO = vmUUID;
this.clusterId = clusterId;
public PrepareExternalProvisioningCommand(VirtualMachineTO vmTO) {
this.virtualMachineTO = vmTO;
}

public VirtualMachineTO getVirtualMachineTO() {
return virtualMachineTO;
}

public Long getClusterId() {
return clusterId;
}

public Map<String, Object> getExternalDetails() {
return externalDetails;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,8 @@
import com.cloud.agent.api.PingRoutingCommand;
import com.cloud.agent.api.PlugNicAnswer;
import com.cloud.agent.api.PlugNicCommand;
import com.cloud.agent.api.PrepareExternalProvisioningAnswer;
import com.cloud.agent.api.PrepareExternalProvisioningCommand;
import com.cloud.agent.api.PrepareForMigrationAnswer;
import com.cloud.agent.api.PrepareForMigrationCommand;
import com.cloud.agent.api.RebootAnswer;
Expand Down Expand Up @@ -1161,6 +1163,70 @@ protected void updateVmMetadataManufacturerAndProduct(VirtualMachineTO vmTO, VMI
vmTO.setMetadataProductName(metadataProduct);
}

protected void updateExternalVmPrepareAnswer(VirtualMachineTO vmTO, VirtualMachineTO updatedTO) {
if (updatedTO == null) {
return;
}
Map<String, NicTO> originalNicsByUuid = new HashMap<>();
for (NicTO nic : vmTO.getNics()) {
originalNicsByUuid.put(nic.getUuid(), nic);
}
for (NicTO updatedNicTO : updatedTO.getNics()) {
if (StringUtils.isNotBlank(updatedNicTO.getMac())) {
NicVO nicVO = _nicsDao.findByUuid(updatedNicTO.getUuid());
if (nicVO == null || Objects.equals(nicVO.getMacAddress(), updatedNicTO.getMac())) {
continue;
}
nicVO.setMacAddress(updatedNicTO.getMac());
_nicsDao.update(nicVO.getId(), nicVO);
NicTO originalNicTO = originalNicsByUuid.get(updatedNicTO.getUuid());
if (originalNicTO != null) {
originalNicTO.setMac(updatedNicTO.getMac());
}
}
}
}

@SuppressWarnings("unchecked")
protected void processPrepareExternalProvisioning(Host host, VirtualMachineTO virtualMachineTO) {
if (host == null || !HypervisorType.External.equals(host.getHypervisorType()) || host.getName() != null) {
return;
}
Map<String, String> vmDetails = virtualMachineTO.getExternalDetails();
Map<String, Object> externalDetails = extensionsManager.getExternalAccessDetails(host,
vmDetails);
Map<String, String> extensionDetails = (Map<String, String>)externalDetails.get(ApiConstants.EXTENSION);
Map<String, String> resourceMapDetails = (Map<String, String>)externalDetails.get(ApiConstants.RESOURCE_MAP);
Map<String, String> hostDetails = (Map<String, String>)externalDetails.get(ApiConstants.EXTENSION);
boolean shouldPrepareVm =
Boolean.parseBoolean(extensionDetails.get(ApiConstants.PREPARE_VM)) ||
Boolean.parseBoolean(resourceMapDetails.get(ApiConstants.PREPARE_VM)) ||
Boolean.parseBoolean(hostDetails.get(ApiConstants.PREPARE_VM));
if (!shouldPrepareVm) {
return;
}
PrepareExternalProvisioningCommand cmd = new PrepareExternalProvisioningCommand(virtualMachineTO);
cmd.setExternalDetails(externalDetails);
Answer answer = null;
try {
answer = _agentMgr.send(host.getId(), cmd);
} catch (AgentUnavailableException | OperationTimedoutException e) {
logger.error("Failed PrepareExternalProvisioningCommand due to : {}", e.getMessage(), e);
return;
}
if (answer == null) {
logger.error("Invalid answer received for PrepareExternalProvisioningCommand");
return;
}
if (!(answer instanceof PrepareExternalProvisioningAnswer)) {
logger.error("Unexpected answer received for PrepareExternalProvisioningCommand: [result: {}, details: {}]",
answer.getResult(), answer.getDetails());
return;
}
PrepareExternalProvisioningAnswer prepareAnswer = (PrepareExternalProvisioningAnswer)answer;
updateExternalVmPrepareAnswer(virtualMachineTO, prepareAnswer.getVirtualMachineTO());
}

@Override
public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfile.Param, Object> params, final DeploymentPlan planToDeploy, final DeploymentPlanner planner)
throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException {
Expand Down Expand Up @@ -1334,6 +1400,7 @@ public void orchestrateStart(final String vmUuid, final Map<VirtualMachineProfil
handlePath(vmTO.getDisks(), vm.getHypervisorType());
setVmNetworkDetails(vm, vmTO);

processPrepareExternalProvisioning(dest.getHost(), vmTO);

Commands cmds = new Commands(Command.OnError.Stop);
final Map<String, String> sshAccessDetails = _networkMgr.getSystemVMAccessDetails(vm);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import javax.naming.ConfigurationException;

import org.apache.cloudstack.acl.ControlledEntity.ACLType;
import org.apache.cloudstack.agent.manager.ExternalAgentManagerImpl;
import org.apache.cloudstack.annotation.AnnotationService;
import org.apache.cloudstack.annotation.dao.AnnotationDao;
import org.apache.cloudstack.api.ApiConstants;
Expand All @@ -60,7 +59,6 @@
import org.apache.cloudstack.network.RoutedIpv4Manager;
import org.apache.cloudstack.network.dao.NetworkPermissionDao;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang3.BooleanUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
Expand All @@ -76,15 +74,12 @@
import com.cloud.agent.api.CleanupPersistentNetworkResourceAnswer;
import com.cloud.agent.api.CleanupPersistentNetworkResourceCommand;
import com.cloud.agent.api.Command;
import com.cloud.agent.api.PrepareExternalProvisioningAnswer;
import com.cloud.agent.api.PrepareExternalProvisioningCommand;
import com.cloud.agent.api.SetupPersistentNetworkAnswer;
import com.cloud.agent.api.SetupPersistentNetworkCommand;
import com.cloud.agent.api.StartupCommand;
import com.cloud.agent.api.StartupRoutingCommand;
import com.cloud.agent.api.routing.NetworkElementCommand;
import com.cloud.agent.api.to.NicTO;
import com.cloud.agent.api.to.VirtualMachineTO;
import com.cloud.agent.api.to.deployasis.OVFNetworkTO;
import com.cloud.alert.AlertManager;
import com.cloud.api.query.dao.DomainRouterJoinDao;
Expand Down Expand Up @@ -132,9 +127,7 @@
import com.cloud.host.Status;
import com.cloud.host.dao.HostDao;
import com.cloud.host.dao.HostDetailsDao;
import com.cloud.hypervisor.Hypervisor;
import com.cloud.hypervisor.Hypervisor.HypervisorType;
import com.cloud.hypervisor.HypervisorGuru;
import com.cloud.hypervisor.HypervisorGuruManager;
import com.cloud.network.IpAddress;
import com.cloud.network.IpAddressManager;
Expand Down Expand Up @@ -264,7 +257,6 @@
import com.cloud.vm.VirtualMachine.Type;
import com.cloud.vm.VirtualMachineManager;
import com.cloud.vm.VirtualMachineProfile;
import com.cloud.vm.VmDetailConstants;
import com.cloud.vm.dao.DomainRouterDao;
import com.cloud.vm.dao.NicDao;
import com.cloud.vm.dao.NicExtraDhcpOptionDao;
Expand Down Expand Up @@ -2239,64 +2231,65 @@ public NicProfile prepareNic(final VirtualMachineProfile vmProfile, final Deploy
}

private void prepareNicIfExternalProvisionerInvolved(VirtualMachineProfile vmProfile, DeployDestination dest, long nicId) {
if (!Hypervisor.HypervisorType.External.equals(vmProfile.getHypervisorType())) {
return;
}
if (userVmDetailsDao.findDetail(vmProfile.getId(), VmDetailConstants.DEPLOY_VM) == null) {
return;
}
HypervisorGuru hvGuru = hvGuruMgr.getGuru(vmProfile.getHypervisorType());
VirtualMachineTO vmTO = hvGuru.implement(vmProfile);

HostVO host = _hostDao.findById(dest.getHost().getId());
PrepareExternalProvisioningCommand command = new PrepareExternalProvisioningCommand(vmTO, host.getClusterId());
Map<String, Object> externalDetails = extensionsManager.getExternalAccessDetails(host, vmTO.getExternalDetails());
command.setExternalDetails(externalDetails);
final PrepareExternalProvisioningAnswer prepareExternalProvisioningAnswer;
try {
Long hostID = dest.getHost().getId();
final Answer answer = _agentMgr.send(hostID, command);

if (!(answer instanceof PrepareExternalProvisioningAnswer)) {
String errorMsg = String.format("Trying to prepare the instance on external hypervisor for the CloudStack instance %s failed: %s", vmProfile.getUuid(), answer.getDetails());
logger.debug(errorMsg);
throw new CloudRuntimeException(errorMsg);
}

prepareExternalProvisioningAnswer = (PrepareExternalProvisioningAnswer) answer;
} catch (AgentUnavailableException | OperationTimedoutException e) {
String errorMsg = String.format("Trying to prepare the instance on external hypervisor for the CloudStack instance %s failed: %s", vmProfile.getUuid(), e);
logger.debug(errorMsg);
throw new CloudRuntimeException(errorMsg);
}

if (prepareExternalProvisioningAnswer == null || !prepareExternalProvisioningAnswer.getResult()) {
if (prepareExternalProvisioningAnswer != null && StringUtils.isNotBlank(prepareExternalProvisioningAnswer.getDetails())) {
throw new CloudRuntimeException(String.format("Unable to prepare the instance on external system due to %s", prepareExternalProvisioningAnswer.getDetails()));
} else {
throw new CloudRuntimeException("Unable to prepare the instance on external system, please check the access details");
}
}

Map<String, String> serverDetails = prepareExternalProvisioningAnswer.getServerDetails();
if (ExternalAgentManagerImpl.expectMacAddressFromExternalProvisioner.valueIn(host.getClusterId())) {
String macAddress = serverDetails.get(VmDetailConstants.MAC_ADDRESS);
if (StringUtils.isEmpty(macAddress)) {
throw new CloudRuntimeException("Unable to fetch macaddress from the external provisioner while preparing the instance");
}
final NicVO nic = _nicDao.findById(nicId);
nic.setMacAddress(macAddress);
_nicDao.update(nicId, nic);
}

if (MapUtils.isNotEmpty(serverDetails)) {
UserVmVO userVm = _userVmDao.findById(vmProfile.getId());
_userVmDao.loadDetails(userVm);
Map<String, String> details = userVm.getDetails();
details.putAll(serverDetails);
userVm.setDetails(details);
_userVmDao.saveDetails(userVm);
}
logger.debug("SimpleEx {}, {}, {}", vmProfile.getId(), dest, nicId);
// if (!Hypervisor.HypervisorType.External.equals(vmProfile.getHypervisorType())) {
// return;
// }
// if (userVmDetailsDao.findDetail(vmProfile.getId(), VmDetailConstants.DEPLOY_VM) == null) {
// return;
// }
// HypervisorGuru hvGuru = hvGuruMgr.getGuru(vmProfile.getHypervisorType());
// VirtualMachineTO vmTO = hvGuru.implement(vmProfile);
//
// HostVO host = _hostDao.findById(dest.getHost().getId());
// PrepareExternalProvisioningCommand command = new PrepareExternalProvisioningCommand(vmTO, host.getClusterId());
// Map<String, Object> externalDetails = extensionsManager.getExternalAccessDetails(host, vmTO.getExternalDetails());
// command.setExternalDetails(externalDetails);
// final PrepareExternalProvisioningAnswer prepareExternalProvisioningAnswer;
// try {
// Long hostID = dest.getHost().getId();
// final Answer answer = _agentMgr.send(hostID, command);
//
// if (!(answer instanceof PrepareExternalProvisioningAnswer)) {
// String errorMsg = String.format("Trying to prepare the instance on external hypervisor for the CloudStack instance %s failed: %s", vmProfile.getUuid(), answer.getDetails());
// logger.debug(errorMsg);
// throw new CloudRuntimeException(errorMsg);
// }
//
// prepareExternalProvisioningAnswer = (PrepareExternalProvisioningAnswer) answer;
// } catch (AgentUnavailableException | OperationTimedoutException e) {
// String errorMsg = String.format("Trying to prepare the instance on external hypervisor for the CloudStack instance %s failed: %s", vmProfile.getUuid(), e);
// logger.debug(errorMsg);
// throw new CloudRuntimeException(errorMsg);
// }
//
// if (prepareExternalProvisioningAnswer == null || !prepareExternalProvisioningAnswer.getResult()) {
// if (prepareExternalProvisioningAnswer != null && StringUtils.isNotBlank(prepareExternalProvisioningAnswer.getDetails())) {
// throw new CloudRuntimeException(String.format("Unable to prepare the instance on external system due to %s", prepareExternalProvisioningAnswer.getDetails()));
// } else {
// throw new CloudRuntimeException("Unable to prepare the instance on external system, please check the access details");
// }
// }
//
// Map<String, String> serverDetails = prepareExternalProvisioningAnswer.getServerDetails();
// if (ExternalAgentManagerImpl.expectMacAddressFromExternalProvisioner.valueIn(host.getClusterId())) {
// String macAddress = serverDetails.get(VmDetailConstants.MAC_ADDRESS);
// if (StringUtils.isEmpty(macAddress)) {
// throw new CloudRuntimeException("Unable to fetch macaddress from the external provisioner while preparing the instance");
// }
// final NicVO nic = _nicDao.findById(nicId);
// nic.setMacAddress(macAddress);
// _nicDao.update(nicId, nic);
// }
//
// if (MapUtils.isNotEmpty(serverDetails)) {
// UserVmVO userVm = _userVmDao.findById(vmProfile.getId());
// _userVmDao.loadDetails(userVm);
// Map<String, String> details = userVm.getDetails();
// details.putAll(serverDetails);
// userVm.setDetails(details);
// _userVmDao.saveDetails(userVm);
// }
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@
import com.cloud.vm.VmDetailConstants;
import com.cloud.vm.dao.UserVmDao;
import com.cloud.vm.dao.VMInstanceDao;
import com.google.gson.JsonSyntaxException;

public class SimpleExternalProvisioner extends ManagerBase implements ExternalProvisioner, PluggableService {

Expand Down Expand Up @@ -267,13 +268,13 @@ public PrepareExternalProvisioningAnswer prepareExternalProvisioning(String host
if (StringUtils.isEmpty(output)) {
return new PrepareExternalProvisioningAnswer(cmd, true, "");
}
Map<String, String> resultMap = null;
VirtualMachineTO virtualMachineTO = null;
try {
resultMap = StringUtils.parseJsonToMap(output);
} catch (CloudRuntimeException e) {
virtualMachineTO = GsonHelper.getGson().fromJson(output, VirtualMachineTO.class);
} catch (JsonSyntaxException e) {
logger.warn("Failed to parse the output from preparing external provisioning operation as part of VM deployment");
}
return new PrepareExternalProvisioningAnswer(cmd, resultMap, null);
return new PrepareExternalProvisioningAnswer(cmd, null, virtualMachineTO, null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,9 +33,18 @@ prepare() {
mac_address=$(generate_random_mac)

local response
response=$(jq -n --arg mac "$mac_address" \
'{status: "success", mac_address: $mac}')

$response='{"nics":['
first=1
while read -r uuid; do
new_mac=$(generate_random_mac)
if [ $first -eq 1 ]; then
first=0
else
$response+=','
fi
$response+='{"uuid":"'"$uuid"'","mac":"'"$new_mac"'"}'
done <<< "$nics_json"
$response+=']}'
echo "$response"
}

Expand Down