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

[VMware] Enable unmanaging guest VMs #4103

Merged
merged 6 commits into from Jun 26, 2020
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
2 changes: 2 additions & 0 deletions api/src/main/java/com/cloud/event/EventTypes.java
Expand Up @@ -102,6 +102,7 @@ public class EventTypes {
public static final String EVENT_VM_RESTORE = "VM.RESTORE";
public static final String EVENT_VM_EXPUNGE = "VM.EXPUNGE";
public static final String EVENT_VM_IMPORT = "VM.IMPORT";
public static final String EVENT_VM_UNMANAGE = "VM.UNMANAGE";

// Domain Router
public static final String EVENT_ROUTER_CREATE = "ROUTER.CREATE";
Expand Down Expand Up @@ -624,6 +625,7 @@ public class EventTypes {
entityEventDetails.put(EVENT_VM_RESTORE, VirtualMachine.class);
entityEventDetails.put(EVENT_VM_EXPUNGE, VirtualMachine.class);
entityEventDetails.put(EVENT_VM_IMPORT, VirtualMachine.class);
entityEventDetails.put(EVENT_VM_UNMANAGE, VirtualMachine.class);

entityEventDetails.put(EVENT_ROUTER_CREATE, VirtualRouter.class);
entityEventDetails.put(EVENT_ROUTER_DESTROY, VirtualRouter.class);
Expand Down
5 changes: 5 additions & 0 deletions api/src/main/java/com/cloud/vm/UserVmService.java
Expand Up @@ -517,4 +517,9 @@ UserVm importVM(final DataCenter zone, final Host host, final VirtualMachineTemp
final long accountId, final long userId, final ServiceOffering serviceOffering, final String sshPublicKey,
final String hostName, final HypervisorType hypervisorType, final Map<String, String> customParameters, final VirtualMachine.PowerState powerState) throws InsufficientCapacityException;

/**
* Unmanage a guest VM from CloudStack
* @return true if the VM is successfully unmanaged, false if not.
*/
boolean unmanageUserVM(Long vmId);
}
1 change: 1 addition & 0 deletions api/src/main/java/com/cloud/vm/VirtualMachineProfile.java
Expand Up @@ -64,6 +64,7 @@ public static class Param {
public static final Param BootMode = new Param("BootMode");
public static final Param BootType = new Param("BootType");
public static final Param BootIntoSetup = new Param("enterHardwareSetup");
public static final Param PreserveNics = new Param("PreserveNics");

private String name;

Expand Down
Expand Up @@ -52,5 +52,5 @@ UserVm revertToSnapshot(Long vmSnapshotId) throws InsufficientServerCapacityExce
* the vm gets deleted on hypervisor (no need to delete each vm snapshot before deleting vm, just mark them as deleted on DB)
* @param id vm id
*/
boolean deleteVMSnapshotsFromDB(Long vmId);
boolean deleteVMSnapshotsFromDB(Long vmId, boolean unmanage);
}
Expand Up @@ -39,6 +39,7 @@
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.vm.VmImportService;
import org.apache.commons.collections.MapUtils;
import org.apache.commons.lang.BooleanUtils;
import org.apache.log4j.Logger;

import com.cloud.event.EventTypes;
Expand Down Expand Up @@ -152,6 +153,11 @@ public class ImportUnmanagedInstanceCmd extends BaseAsyncCmd {
description = "vm and its volumes are allowed to migrate to different host/pool when offerings passed are incompatible with current host/pool")
private Boolean migrateAllowed;

@Parameter(name = ApiConstants.FORCED,
type = CommandType.BOOLEAN,
description = "VM is imported despite some of its NIC's MAC addresses are already present")
private Boolean forced;

/////////////////////////////////////////////////////
/////////////////// Accessors ///////////////////////
/////////////////////////////////////////////////////
Expand Down Expand Up @@ -268,6 +274,10 @@ public String getEventDescription() {
return "Importing unmanaged VM";
}

public boolean isForced() {
return BooleanUtils.isTrue(forced);
}

/////////////////////////////////////////////////////
/////////////// API Implementation///////////////////
/////////////////////////////////////////////////////
Expand Down
@@ -0,0 +1,136 @@
//
// 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.vm;

import com.cloud.event.EventTypes;
import com.cloud.exception.ConcurrentOperationException;
import com.cloud.exception.InsufficientCapacityException;
import com.cloud.exception.NetworkRuleConflictException;
import com.cloud.exception.ResourceAllocationException;
import com.cloud.exception.ResourceUnavailableException;
import com.cloud.user.Account;
import com.cloud.uservm.UserVm;
import com.cloud.vm.VirtualMachine;
import org.apache.cloudstack.acl.RoleType;
import org.apache.cloudstack.api.APICommand;
import org.apache.cloudstack.api.ApiCommandJobType;
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.ServerApiException;
import org.apache.cloudstack.api.response.UnmanageVMInstanceResponse;
import org.apache.cloudstack.api.response.UserVmResponse;
import org.apache.cloudstack.context.CallContext;
import org.apache.cloudstack.vm.UnmanagedVMsManager;
import org.apache.log4j.Logger;

import javax.inject.Inject;

@APICommand(name = UnmanageVMInstanceCmd.API_NAME,
description = "Unmanage a guest virtual machine.",
entityType = {VirtualMachine.class},
responseObject = UnmanageVMInstanceResponse.class,
requestHasSensitiveInfo = false,
authorized = {RoleType.Admin},
since = "4.15.0")
public class UnmanageVMInstanceCmd extends BaseAsyncCmd {

public static final Logger LOGGER = Logger.getLogger(UnmanageVMInstanceCmd.class);
public static final String API_NAME = "unmanageVirtualMachine";

@Inject
private UnmanagedVMsManager unmanagedVMsManager;

/////////////////////////////////////////////////////
//////////////// API parameters /////////////////////
/////////////////////////////////////////////////////

@Parameter(name = ApiConstants.ID, type = CommandType.UUID,
entityType = UserVmResponse.class, required = true,
description = "The ID of the virtual machine to unmanage")
private Long vmId;

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

public Long getVmId() {
return vmId;
}

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

@Override
public String getEventDescription() {
return "unmanaging VM. VM ID = " + vmId;
}

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

@Override
public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException,
ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException {
UnmanageVMInstanceResponse response = new UnmanageVMInstanceResponse();
try {
CallContext.current().setEventDetails("VM ID = " + vmId);
boolean result = unmanagedVMsManager.unmanageVMInstance(vmId);
response.setSuccess(result);
if (result) {
response.setDetails("VM unmanaged successfully");
}
} catch (Exception e) {
throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, e.getMessage());
}
response.setResponseName(getCommandName());
response.setObjectName(getCommandName());
this.setResponseObject(response);
}

@Override
public String getCommandName() {
return API_NAME.toLowerCase() + BaseAsyncCmd.RESPONSE_SUFFIX;
}

@Override
public long getEntityOwnerId() {
UserVm vm = _responseGenerator.findUserVmById(vmId);
if (vm != null) {
return vm.getAccountId();
}
return Account.ACCOUNT_ID_SYSTEM;
}

@Override
public ApiCommandJobType getInstanceType() {
return ApiCommandJobType.VirtualMachine;
}

@Override
public Long getInstanceId() {
return vmId;
}

}
@@ -0,0 +1,58 @@
// 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.response;

import com.cloud.serializer.Param;
import com.google.gson.annotations.SerializedName;
import org.apache.cloudstack.api.ApiConstants;
import org.apache.cloudstack.api.BaseResponse;

public class UnmanageVMInstanceResponse extends BaseResponse {

@SerializedName(ApiConstants.RESULT)
@Param(description = "result of the unmanage VM operation")
private boolean success;

@SerializedName(ApiConstants.DETAILS)
@Param(description = "details of the unmanage VM operation")
private String details;

public UnmanageVMInstanceResponse() {
}

public UnmanageVMInstanceResponse(boolean success, String details) {
this.success = success;
this.details = details;
}

public boolean isSuccess() {
return success;
}

public void setSuccess(boolean success) {
this.success = success;
}

public String getDetails() {
return details;
}

public void setDetails(String details) {
this.details = details;
}
}
27 changes: 27 additions & 0 deletions api/src/main/java/org/apache/cloudstack/vm/UnmanageVMService.java
@@ -0,0 +1,27 @@
// 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.vm;

public interface UnmanageVMService {

/**
* Unmanage a guest VM from CloudStack
* @return true if the VM is successfully unmanaged, false if not.
*/
boolean unmanageVMInstance(long vmId);
}
@@ -0,0 +1,29 @@
// 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.vm;

import com.cloud.utils.component.PluggableService;
import org.apache.cloudstack.framework.config.ConfigKey;
import org.apache.cloudstack.framework.config.Configurable;

public interface UnmanagedVMsManager extends VmImportService, UnmanageVMService, PluggableService, Configurable {

ConfigKey<Boolean> UnmanageVMPreserveNic = new ConfigKey<>("Advanced", Boolean.class, "unmanage.vm.preserve.nics", "false",
"If set to true, do not remove VM nics (and its MAC addresses) when unmanaging a VM, leaving them allocated but not reserved. " +
"If set to false, nics are removed and MAC addresses can be reassigned", true, ConfigKey.Scope.Zone);
}
Expand Up @@ -23,9 +23,7 @@
import org.apache.cloudstack.api.response.UnmanagedInstanceResponse;
import org.apache.cloudstack.api.response.UserVmResponse;

import com.cloud.utils.component.PluggableService;

public interface VmImportService extends PluggableService {
public interface VmImportService {
ListResponse<UnmanagedInstanceResponse> listUnmanagedInstances(ListUnmanagedInstancesCmd cmd);
UserVmResponse importUnmanagedInstance(ImportUnmanagedInstanceCmd cmd);
}
@@ -0,0 +1,27 @@
// 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 com.cloud.agent.api;

public class PrepareUnmanageVMInstanceAnswer extends Answer {

public PrepareUnmanageVMInstanceAnswer() {
}

public PrepareUnmanageVMInstanceAnswer(PrepareUnmanageVMInstanceCommand cmd, boolean result, String details) {
super(cmd, result, details);
}
}