diff --git a/api/src/main/java/com/cloud/server/ManagementService.java b/api/src/main/java/com/cloud/server/ManagementService.java index 96547818e737..0973a3299275 100644 --- a/api/src/main/java/com/cloud/server/ManagementService.java +++ b/api/src/main/java/com/cloud/server/ManagementService.java @@ -35,7 +35,13 @@ import org.apache.cloudstack.api.command.admin.guest.UpdateGuestOsMappingCmd; import org.apache.cloudstack.api.command.admin.host.ListHostsCmd; import org.apache.cloudstack.api.command.admin.host.UpdateHostPasswordCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.LicenseCheckCmd; import org.apache.cloudstack.api.command.admin.outofbandmanagement.ListHostDevicesCmd; +// import org.apache.cloudstack.api.command.admin.outofbandmanagement.ListHostLunDevicesCmd; +// import org.apache.cloudstack.api.command.admin.outofbandmanagement.ListHostUsbDevicesCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.UpdateHostDevicesCmd; +// import org.apache.cloudstack.api.command.admin.outofbandmanagement.UpdateHostLunDevicesCmd; +// import org.apache.cloudstack.api.command.admin.outofbandmanagement.UpdateHostUsbDevicesCmd; import org.apache.cloudstack.api.command.admin.pod.ListPodsByCmd; import org.apache.cloudstack.api.command.admin.resource.ArchiveAlertsCmd; import org.apache.cloudstack.api.command.admin.resource.DeleteAlertsCmd; @@ -66,10 +72,14 @@ import org.apache.cloudstack.api.command.user.userdata.RegisterUserDataCmd; import org.apache.cloudstack.api.command.user.vm.GetVMPasswordCmd; import org.apache.cloudstack.api.command.user.vmgroup.UpdateVMGroupCmd; -import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.LicenseCheckerResponse; -import org.apache.cloudstack.api.command.admin.outofbandmanagement.LicenseCheckCmd; import org.apache.cloudstack.api.response.ListHostDevicesResponse; +// import org.apache.cloudstack.api.response.ListHostLunDevicesResponse; +// import org.apache.cloudstack.api.response.ListHostUsbDevicesResponse; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.UpdateHostDevicesResponse; +// import org.apache.cloudstack.api.response.UpdateHostLunDevicesResponse; +// import org.apache.cloudstack.api.response.UpdateHostUsbDevicesResponse; import org.apache.cloudstack.config.Configuration; import org.apache.cloudstack.config.ConfigurationGroup; @@ -97,6 +107,7 @@ import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachine.Type; + /** * Hopefully this is temporary. * @@ -496,6 +507,16 @@ VirtualMachine upgradeSystemVM(ScaleSystemVMCmd cmd) throws ResourceUnavailableE ListResponse listHostDevices(ListHostDevicesCmd cmd); + ListResponse updateHostDevices(UpdateHostDevicesCmd cmd); + + // ListResponse listHostUsbDevices(ListHostUsbDevicesCmd cmd); + + // ListResponse listHostLunDevices(ListHostLunDevicesCmd cmd); + + // ListResponse updateHostUsbDevices(UpdateHostUsbDevicesCmd cmd); + + // ListResponse updateHostLunDevices(UpdateHostLunDevicesCmd cmd); + LicenseCheckerResponse checkLicense(LicenseCheckCmd cmd); } \ No newline at end of file diff --git a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java index 61c2543580be..541628c0b501 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -1307,6 +1307,8 @@ public class ApiConstants { public static final String LICENSE_CHECK = "licensecheck"; public static final String HAS_LICENSE = "haslicense"; public static final String ISSUED_DATE = "issueddate"; + public static final String XML_CONFIG = "xmlconfig"; + public static final String CURRENT_VM_ID = "currentvmid"; /** * This enum specifies IO Drivers, each option controls specific policies on I/O. * Qemu guests support "threads" and "native" options Since 0.8.8 ; "io_uring" is supported Since 6.3.0 (QEMU 5.0). diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/ListHostLunDevicesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/ListHostLunDevicesCmd.java new file mode 100644 index 000000000000..f8d64e31cec7 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/ListHostLunDevicesCmd.java @@ -0,0 +1,73 @@ +// 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.outofbandmanagement; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.ListHostLunDevicesResponse; +import org.apache.cloudstack.context.CallContext; +// import org.apache.cloudstack.api.response.ListResponse; + + + +@APICommand(name = "listHostLunDevices", description = "list Host LUN Devices'.", since = "4.20.0.0", responseObject = ListHostLunDevicesResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = { RoleType.Admin }) +public class ListHostLunDevicesCmd extends BaseListCmd { + + private static final String LISTHOSTLUNDEVICES = "listhostusbdevices"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, entityType = ListHostLunDevicesResponse.class, description = "host ID", required = true, validations = { + ApiArgValidator.PositiveNumber }) + private Long id; + + ///////////////////////////////////////////////////// + /////////////////// Accessors ///////////////////////a + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + public static String getResultObjectName() { + return "listhostusbdevices"; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public void execute() { + // ListResponse response = _mgr.listHostLunDevices(this); + // response.setResponseName(getCommandName()); + // response.setObjectName(getCommandName()); + // this.setResponseObject(response); + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/ListHostUsbDevicesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/ListHostUsbDevicesCmd.java new file mode 100644 index 000000000000..7f42d44a0ff5 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/ListHostUsbDevicesCmd.java @@ -0,0 +1,73 @@ +// 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.outofbandmanagement; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.ListHostUsbDevicesResponse; +import org.apache.cloudstack.context.CallContext; +// import org.apache.cloudstack.api.response.ListResponse; + + + +@APICommand(name = "listHostUsbDevices", description = "list Host USB Devices'.", since = "4.20.0.0", responseObject = ListHostUsbDevicesResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = { RoleType.Admin }) +public class ListHostUsbDevicesCmd extends BaseListCmd { + + private static final String LISTHOSTUSBDEVICES = "listhostusbdevices"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.ID, type = BaseCmd.CommandType.UUID, entityType = ListHostUsbDevicesResponse.class, description = "host ID", required = true, validations = { + ApiArgValidator.PositiveNumber }) + private Long id; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getId() { + return id; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + public static String getResultObjectName() { + return "listhostusbdevices"; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public void execute() { + // ListResponse response = _mgr.listHostUsbDevices(this); + // response.setResponseName(getCommandName()); + // response.setObjectName(getCommandName()); + // this.setResponseObject(response); + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/UpdateHostDevicesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/UpdateHostDevicesCmd.java new file mode 100644 index 000000000000..aeaac68cbf4f --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/UpdateHostDevicesCmd.java @@ -0,0 +1,115 @@ +// 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.outofbandmanagement; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.UpdateHostDevicesResponse; +import org.apache.cloudstack.context.CallContext; +// import org.apache.cloudstack.api.response.HostResponse; + +@APICommand(name = "updateHostDevices", description = "list Host Devices'.", since = "4.20.0.0", responseObject = UpdateHostDevicesResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = { + RoleType.Admin }) +public class UpdateHostDevicesCmd extends BaseListCmd { + + private static final String UPDATEHOSTDEVICES = "updatehostdevices"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.HOST_ID, type = BaseCmd.CommandType.UUID, entityType = UpdateHostDevicesResponse.class, description = "host ID", required = true, validations = { + ApiArgValidator.PositiveNumber }) + private Long hostId; + + @Parameter(name = ApiConstants.HOSTDEVICES_NAME, type = CommandType.STRING, required = true, + description = "Device name to allocate") + private String hostDeviceName; + + @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, + entityType = UpdateHostDevicesResponse.class, + required = false, description = "VM ID to allocate the device to") + private Long vmId; + + @Parameter(name = ApiConstants.XML_CONFIG, type = CommandType.STRING, required = false, + description = "XML configuration for device attachment") + private String xmlConfig; + + @Parameter(name = ApiConstants.CURRENT_VM_ID, type = CommandType.STRING, required = false, + description = "Current VM ID") + private String currentVmId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getHostId() { + return hostId; + } + + public String getHostDeviceName() { + return hostDeviceName; + } + + public Long getVirtualMachineId() { + return vmId; + } + + public String getXmlConfig() { + return xmlConfig; + } + + public void setXmlConfig(String xmlConfig) { + this.xmlConfig = xmlConfig; + } + + public String getCurrentVmId() { + return currentVmId; + } + + public void setCurrentVmId(String currentVmId) { + this.currentVmId = currentVmId; + } + + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + public static String getResultObjectName() { + return "updatehostdevices"; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public void execute() { + ListResponse response = _mgr.updateHostDevices(this); + response.setResponseName(getCommandName()); + response.setObjectName(getCommandName()); + this.setResponseObject(response); + } +} \ No newline at end of file diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/UpdateHostLunDevicesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/UpdateHostLunDevicesCmd.java new file mode 100644 index 000000000000..66c0bad6e278 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/UpdateHostLunDevicesCmd.java @@ -0,0 +1,114 @@ +// 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.outofbandmanagement; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.UpdateHostLunDevicesResponse; +import org.apache.cloudstack.context.CallContext; +// import org.apache.cloudstack.api.response.ListResponse; +// import org.apache.cloudstack.api.response.HostResponse; + +@APICommand(name = "updateHostLunDevices", description = "list Host Lun Devices'.", since = "4.20.0.0", responseObject = UpdateHostLunDevicesResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = { + RoleType.Admin }) +public class UpdateHostLunDevicesCmd extends BaseListCmd { + + private static final String UPDATEHOSTDEVICES = "updatehostdevices"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.HOST_ID, type = BaseCmd.CommandType.UUID, entityType = UpdateHostLunDevicesResponse.class, description = "host ID", required = true, validations = { + ApiArgValidator.PositiveNumber }) + private Long hostId; + + @Parameter(name = ApiConstants.HOSTDEVICES_NAME, type = CommandType.STRING, required = true, + description = "Device name to allocate") + private String hostDeviceName; + + @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, + entityType = UpdateHostLunDevicesResponse.class, + required = false, description = "VM ID to allocate the device to") + private Long vmId; + + @Parameter(name = ApiConstants.XML_CONFIG, type = CommandType.STRING, required = false, + description = "XML configuration for device attachment") + private String xmlConfig; + + @Parameter(name = ApiConstants.CURRENT_VM_ID, type = CommandType.STRING, required = false, + description = "Current VM ID") + private String currentVmId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getHostId() { + return hostId; + } + + public String getHostDeviceName() { + return hostDeviceName; + } + + public Long getVirtualMachineId() { + return vmId; + } + + public String getXmlConfig() { + return xmlConfig; + } + + public void setXmlConfig(String xmlConfig) { + this.xmlConfig = xmlConfig; + } + + public String getCurrentVmId() { + return currentVmId; + } + + public void setCurrentVmId(String currentVmId) { + this.currentVmId = currentVmId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + public static String getResultObjectName() { + return "updatehostdevices"; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public void execute() { + // ListResponse response = _mgr.updateHostLunDevices(this); + // response.setResponseName(getCommandName()); + // response.setObjectName(getCommandName()); + // this.setResponseObject(response); + } +} \ No newline at end of file diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/UpdateHostUsbDevicesCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/UpdateHostUsbDevicesCmd.java new file mode 100644 index 000000000000..3f4cc921ff44 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/outofbandmanagement/UpdateHostUsbDevicesCmd.java @@ -0,0 +1,114 @@ +// 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.outofbandmanagement; + +import org.apache.cloudstack.acl.RoleType; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiArgValidator; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.BaseListCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.response.UpdateHostUsbDevicesResponse; +import org.apache.cloudstack.context.CallContext; +// import org.apache.cloudstack.api.response.ListResponse; +// import org.apache.cloudstack.api.response.HostResponse; + +@APICommand(name = "updateHostUsbDevices", description = "list Host Usb Devices'.", since = "4.20.0.0", responseObject = UpdateHostUsbDevicesResponse.class, requestHasSensitiveInfo = false, responseHasSensitiveInfo = false, authorized = { + RoleType.Admin }) +public class UpdateHostUsbDevicesCmd extends BaseListCmd { + + private static final String UPDATEHOSTDEVICES = "updatehostdevices"; + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.HOST_ID, type = BaseCmd.CommandType.UUID, entityType = UpdateHostUsbDevicesResponse.class, description = "host ID", required = true, validations = { + ApiArgValidator.PositiveNumber }) + private Long hostId; + + @Parameter(name = ApiConstants.HOSTDEVICES_NAME, type = CommandType.STRING, required = true, + description = "Device name to allocate") + private String hostDeviceName; + + @Parameter(name = ApiConstants.VIRTUAL_MACHINE_ID, type = CommandType.UUID, + entityType = UpdateHostUsbDevicesResponse.class, + required = false, description = "VM ID to allocate the device to") + private Long vmId; + + @Parameter(name = ApiConstants.XML_CONFIG, type = CommandType.STRING, required = false, + description = "XML configuration for device attachment") + private String xmlConfig; + + @Parameter(name = ApiConstants.CURRENT_VM_ID, type = CommandType.STRING, required = false, + description = "Current VM ID") + private String currentVmId; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + public Long getHostId() { + return hostId; + } + + public String getHostDeviceName() { + return hostDeviceName; + } + + public Long getVirtualMachineId() { + return vmId; + } + + public String getXmlConfig() { + return xmlConfig; + } + + public void setXmlConfig(String xmlConfig) { + this.xmlConfig = xmlConfig; + } + + public String getCurrentVmId() { + return currentVmId; + } + + public void setCurrentVmId(String currentVmId) { + this.currentVmId = currentVmId; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + public static String getResultObjectName() { + return "updatehostdevices"; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccountId(); + } + + @Override + public void execute() { + // ListResponse response = _mgr.updateHostUsbDevices(this); + // response.setResponseName(getCommandName()); + // response.setObjectName(getCommandName()); + // this.setResponseObject(response); + } +} \ No newline at end of file diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ListHostDevicesResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ListHostDevicesResponse.java index a81bf191a80e..7b0e4b478369 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/ListHostDevicesResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/ListHostDevicesResponse.java @@ -21,6 +21,7 @@ import com.cloud.serializer.Param; import com.google.gson.annotations.SerializedName; import java.util.List; +import java.util.Map; import org.apache.cloudstack.api.ApiConstants; import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; @@ -37,6 +38,10 @@ public class ListHostDevicesResponse extends BaseResponse { @Param(description = "the ID of the pod the IP address belongs to") private List hostDevicesText; + @SerializedName("vmallocations") + @Param(description = "Map of device to VM allocations") + private Map vmAllocations; + public ListHostDevicesResponse(List hostDevicesName, List hostDevicesText) { this.hostDevicesName = hostDevicesName; this.hostDevicesText = hostDevicesText; @@ -63,4 +68,12 @@ public void setHostDevicesTexts(List hostDevicesText) { this.hostDevicesText = hostDevicesText; } + public void setVmAllocations(Map vmAllocations) { + this.vmAllocations = vmAllocations; + } + + public Map getVmAllocations() { + return this.vmAllocations; + } + } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ListHostLunDevicesResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ListHostLunDevicesResponse.java new file mode 100644 index 000000000000..91ada96f2e4a --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/response/ListHostLunDevicesResponse.java @@ -0,0 +1,97 @@ +//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.host.Host; +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +@EntityReference(value = Host.class) +public class ListHostLunDevicesResponse extends BaseResponse { + + @SerializedName(ApiConstants.HOSTDEVICES_NAME) + @Param(description = "Device names") + private List hostDevicesName; + + @SerializedName(ApiConstants.HOSTDEVICES_TEXT) + @Param(description = "Device descriptions") + private List hostDevicesText; + + @SerializedName("vmallocations") + @Param(description = "Map of device to VM allocations") + private Map vmAllocations; + + @SerializedName("haspartitions") + @Param(description = "Map of devices indicating whether they have partitions") + private Map partitionInfo = new HashMap<>(); + + public ListHostLunDevicesResponse(List hostDevicesName, List hostDevicesText) { + this.hostDevicesName = hostDevicesName; + this.hostDevicesText = hostDevicesText; + } + + public ListHostLunDevicesResponse() { + super(); + this.setObjectName("listhostlundevices"); + } + + public List getHostDevicesNames() { + return hostDevicesName; + } + + public List getHostDevicesTexts() { + return hostDevicesText; + } + + public void setHostDevicesNames(List hostDevicesName) { + this.hostDevicesName = hostDevicesName; + } + + public void setHostDevicesTexts(List hostDevicesText) { + this.hostDevicesText = hostDevicesText; + } + + public void setVmAllocations(Map vmAllocations) { + this.vmAllocations = vmAllocations; + } + + public Map getVmAllocations() { + return this.vmAllocations; + } + + public Map getPartitionInfo() { + return partitionInfo; + } + + public void setPartitionInfo(Map partitionInfo) { + this.partitionInfo = partitionInfo; + } + + public void addPartitionInfo(String deviceName, boolean hasPartition) { + if (this.partitionInfo == null) { + this.partitionInfo = new HashMap<>(); + } + this.partitionInfo.put(deviceName, hasPartition); + } +} diff --git a/api/src/main/java/org/apache/cloudstack/api/response/ListHostUsbDevicesResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/ListHostUsbDevicesResponse.java new file mode 100644 index 000000000000..f096852e1e44 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/response/ListHostUsbDevicesResponse.java @@ -0,0 +1,79 @@ +// //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.host.Host; +// import com.cloud.serializer.Param; +// import com.google.gson.annotations.SerializedName; +// import java.util.List; +// import java.util.Map; +// import org.apache.cloudstack.api.ApiConstants; +// import org.apache.cloudstack.api.BaseResponse; +// import org.apache.cloudstack.api.EntityReference; + + +// @EntityReference(value = Host.class) +// public class ListHostUsbDevicesResponse extends BaseResponse { + +// @SerializedName(ApiConstants.HOSTDEVICES_NAME) +// @Param(description = "Allocated IP address") +// private List hostDevicesName; + +// @SerializedName(ApiConstants.HOSTDEVICES_TEXT) +// @Param(description = "the ID of the pod the IP address belongs to") +// private List hostDevicesText; + +// @SerializedName("vmallocations") +// @Param(description = "Map of device to VM allocations") +// private Map vmAllocations; + +// public ListHostUsbDevicesResponse(List hostDevicesName, List hostDevicesText) { +// this.hostDevicesName = hostDevicesName; +// this.hostDevicesText = hostDevicesText; +// } + +// public ListHostUsbDevicesResponse() { +// super(); +// this.setObjectName("listhostusbdevices"); +// } + +// public List getHostDevicesNames() { +// return hostDevicesName; +// } + +// public List getHostDevicesTexts() { +// return hostDevicesText; +// } + +// public void setHostDevicesNames(List hostDevicesName) { +// this.hostDevicesName = hostDevicesName; +// } + +// public void setHostDevicesTexts(List hostDevicesText) { +// this.hostDevicesText = hostDevicesText; +// } + +// public void setVmAllocations(Map vmAllocations) { +// this.vmAllocations = vmAllocations; +// } + +// public Map getVmAllocations() { +// return this.vmAllocations; +// } + +// } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/UpdateHostDevicesResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/UpdateHostDevicesResponse.java new file mode 100644 index 000000000000..caeb5d9075f4 --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/response/UpdateHostDevicesResponse.java @@ -0,0 +1,78 @@ +// 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.host.Host; +import com.cloud.serializer.Param; +import com.cloud.vm.VirtualMachine; +import com.google.gson.annotations.SerializedName; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +@EntityReference(value = {Host.class, VirtualMachine.class}) +public class UpdateHostDevicesResponse extends BaseResponse { + + @SerializedName(ApiConstants.HOSTDEVICES_NAME) + @Param(description = "Device name") + private String hostDevicesName; + + @SerializedName(ApiConstants.VIRTUAL_MACHINE_ID) + @Param(description = "ID of the VM the device is allocated to") + private String virtualmachineid; + + @SerializedName("allocated") + @Param(description = "Whether the device is allocated") + private boolean allocated; + + public UpdateHostDevicesResponse(String hostDevicesName, String virtualmachineid, boolean allocated) { + this.hostDevicesName = hostDevicesName; + this.virtualmachineid = virtualmachineid; + this.allocated = allocated; +} + + public UpdateHostDevicesResponse() { + super(); + setObjectName("updatehostdevices"); + } + + public String getHostDeviceName() { + return hostDevicesName; + } + + public void setHostDeviceName(String deviceName) { + this.hostDevicesName = deviceName; + } + + public String getVirtualMachineId() { + return virtualmachineid; + } + + public void setVirtualMachineId(String virtualmachineid) { + this.virtualmachineid = virtualmachineid; + } + + public boolean isAllocated() { + return allocated; + } + + public void setAllocated(boolean allocated) { + this.allocated = allocated; + } +} \ No newline at end of file diff --git a/api/src/main/java/org/apache/cloudstack/api/response/UpdateHostLunDevicesResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/UpdateHostLunDevicesResponse.java new file mode 100644 index 000000000000..6668eaa685aa --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/response/UpdateHostLunDevicesResponse.java @@ -0,0 +1,78 @@ +// 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.host.Host; +import com.cloud.serializer.Param; +import com.cloud.vm.VirtualMachine; +import com.google.gson.annotations.SerializedName; + +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + +@EntityReference(value = {Host.class, VirtualMachine.class}) +public class UpdateHostLunDevicesResponse extends BaseResponse { + + @SerializedName(ApiConstants.HOSTDEVICES_NAME) + @Param(description = "Device name") + private String hostDevicesName; + + @SerializedName(ApiConstants.VIRTUAL_MACHINE_ID) + @Param(description = "ID of the VM the device is allocated to") + private String virtualmachineid; + + @SerializedName("allocated") + @Param(description = "Whether the device is allocated") + private boolean allocated; + + public UpdateHostLunDevicesResponse(String hostDevicesName, String virtualmachineid, boolean allocated) { + this.hostDevicesName = hostDevicesName; + this.virtualmachineid = virtualmachineid; + this.allocated = allocated; +} + + public UpdateHostLunDevicesResponse() { + super(); + setObjectName("updatehostdevices"); + } + + public String getHostDeviceName() { + return hostDevicesName; + } + + public void setHostDeviceName(String deviceName) { + this.hostDevicesName = deviceName; + } + + public String getVirtualMachineId() { + return virtualmachineid; + } + + public void setVirtualMachineId(String virtualmachineid) { + this.virtualmachineid = virtualmachineid; + } + + public boolean isAllocated() { + return allocated; + } + + public void setAllocated(boolean allocated) { + this.allocated = allocated; + } +} \ No newline at end of file diff --git a/api/src/main/java/org/apache/cloudstack/api/response/UpdateHostUsbDevicesResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/UpdateHostUsbDevicesResponse.java new file mode 100644 index 000000000000..66665e87c09c --- /dev/null +++ b/api/src/main/java/org/apache/cloudstack/api/response/UpdateHostUsbDevicesResponse.java @@ -0,0 +1,78 @@ +// 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.host.Host; +import com.cloud.serializer.Param; +import com.cloud.vm.VirtualMachine; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; +import org.apache.cloudstack.api.EntityReference; + + +@EntityReference(value = {Host.class, VirtualMachine.class}) +public class UpdateHostUsbDevicesResponse extends BaseResponse { + + @SerializedName(ApiConstants.HOSTDEVICES_NAME) + @Param(description = "Device name") + private String hostDevicesName; + + @SerializedName(ApiConstants.VIRTUAL_MACHINE_ID) + @Param(description = "ID of the VM the device is allocated to") + private String virtualmachineid; + + @SerializedName("allocated") + @Param(description = "Whether the device is allocated") + private boolean allocated; + + public UpdateHostUsbDevicesResponse(String hostDevicesName, String virtualmachineid, boolean allocated) { + this.hostDevicesName = hostDevicesName; + this.virtualmachineid = virtualmachineid; + this.allocated = allocated; +} + + public UpdateHostUsbDevicesResponse() { + super(); + setObjectName("updatehostdevices"); + } + + public String getHostDeviceName() { + return hostDevicesName; + } + + public void setHostDeviceName(String deviceName) { + this.hostDevicesName = deviceName; + } + + public String getVirtualMachineId() { + return virtualmachineid; + } + + public void setVirtualMachineId(String virtualmachineid) { + this.virtualmachineid = virtualmachineid; + } + + public boolean isAllocated() { + return allocated; + } + + public void setAllocated(boolean allocated) { + this.allocated = allocated; + } +} \ No newline at end of file diff --git a/core/src/main/java/com/cloud/agent/api/ListHostDeviceAnswer.java b/core/src/main/java/com/cloud/agent/api/ListHostDeviceAnswer.java index 010929faad93..0e120af95fa2 100644 --- a/core/src/main/java/com/cloud/agent/api/ListHostDeviceAnswer.java +++ b/core/src/main/java/com/cloud/agent/api/ListHostDeviceAnswer.java @@ -24,18 +24,27 @@ public class ListHostDeviceAnswer extends Answer { private boolean successMessage; + private List hostDevicesNames; private List hostDevicesText; public ListHostDeviceAnswer() { super(); } - public ListHostDeviceAnswer(boolean successMessage, List hostDevicesText) { + public ListHostDeviceAnswer(boolean successMessage, List hostDevicesNames, List hostDevicesText) { super(); this.successMessage = successMessage; + this.hostDevicesNames = hostDevicesNames; this.hostDevicesText = hostDevicesText; } + public List getHostDevicesNames() { + if (hostDevicesText == null) { + return Collections.emptyList(); + } + return hostDevicesNames; + } + public List getHostDevicesTexts() { if (hostDevicesText == null) { return Collections.emptyList(); diff --git a/core/src/main/java/com/cloud/agent/api/ListHostDeviceCommand.java b/core/src/main/java/com/cloud/agent/api/ListHostDeviceCommand.java index 2b80fd633531..31ccddc65f1a 100644 --- a/core/src/main/java/com/cloud/agent/api/ListHostDeviceCommand.java +++ b/core/src/main/java/com/cloud/agent/api/ListHostDeviceCommand.java @@ -51,4 +51,8 @@ public List getHostDevicesText() { public Long getId() { return id; } + + public void setHostDevicesName(List hostDevicesName) { + this.hostDevicesName = hostDevicesName; + } } diff --git a/core/src/main/java/com/cloud/agent/api/ListHostLunDeviceAnswer.java b/core/src/main/java/com/cloud/agent/api/ListHostLunDeviceAnswer.java new file mode 100644 index 000000000000..eae00d3e9efa --- /dev/null +++ b/core/src/main/java/com/cloud/agent/api/ListHostLunDeviceAnswer.java @@ -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 com.cloud.agent.api; + +// import java.util.Collections; +import java.util.List; + +public class ListHostLunDeviceAnswer extends Answer { + private List hostDevicesNames; + private List hostDevicesTexts; + private List hasPartitions; + + public ListHostLunDeviceAnswer(boolean success, List hostDevicesNames, List hostDevicesTexts, List hasPartitions) { + super(); + this.hostDevicesNames = hostDevicesNames; + this.hostDevicesTexts = hostDevicesTexts; + this.hasPartitions = hasPartitions; + } + + // Getters and setters + public List getHostDevicesNames() { + return hostDevicesNames; + } + + public void setHostDevicesNames(List hostDevicesNames) { + this.hostDevicesNames = hostDevicesNames; + } + + public List getHostDevicesTexts() { + return hostDevicesTexts; + } + + public void setHostDevicesTexts(List hostDevicesTexts) { + this.hostDevicesTexts = hostDevicesTexts; + } + + public List getHasPartitions() { + return hasPartitions; + } + +} diff --git a/core/src/main/java/com/cloud/agent/api/ListHostLunDeviceCommand.java b/core/src/main/java/com/cloud/agent/api/ListHostLunDeviceCommand.java new file mode 100644 index 000000000000..febe1b5f9b18 --- /dev/null +++ b/core/src/main/java/com/cloud/agent/api/ListHostLunDeviceCommand.java @@ -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 com.cloud.agent.api; + +import java.util.List; + +public class ListHostLunDeviceCommand extends Command { + + private final Long id; + private List hostDevicesName; + private List hostDevicesText; + + public ListHostLunDeviceCommand(Long id) { + this.id = id; + } + + @Override + public boolean executeInSequence() { + return false; + } + + public Long getId() { + return id; + } + + public List getHostDevicesName() { + return hostDevicesName; + } + + public void setHostDevicesName(List hostDevicesName) { + this.hostDevicesName = hostDevicesName; + } + + public List getHostDevicesText() { + return hostDevicesText; + } + + public void setHostDevicesText(List hostDevicesText) { + this.hostDevicesText = hostDevicesText; + } +} diff --git a/core/src/main/java/com/cloud/agent/api/ListHostUsbDeviceAnswer.java b/core/src/main/java/com/cloud/agent/api/ListHostUsbDeviceAnswer.java new file mode 100644 index 000000000000..f47b4f1e1d9e --- /dev/null +++ b/core/src/main/java/com/cloud/agent/api/ListHostUsbDeviceAnswer.java @@ -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 com.cloud.agent.api; + +import java.util.Collections; +import java.util.List; + +public class ListHostUsbDeviceAnswer extends Answer { + private boolean successMessage; + private List hostDevicesNames; + private List hostDevicesText; + + public ListHostUsbDeviceAnswer() { + super(); + } + + public ListHostUsbDeviceAnswer(boolean successMessage, List hostDevicesNames, List hostDevicesText) { + super(); + this.successMessage = successMessage; + this.hostDevicesNames = hostDevicesNames; + this.hostDevicesText = hostDevicesText; + } + + public List getHostDevicesNames() { + if (hostDevicesText == null) { + return Collections.emptyList(); + } + return hostDevicesNames; + } + + public List getHostDevicesTexts() { + if (hostDevicesText == null) { + return Collections.emptyList(); + } + return hostDevicesText; + } + + public boolean isSuccessMessage() { + return successMessage; + } +} diff --git a/core/src/main/java/com/cloud/agent/api/ListHostUsbDeviceCommand.java b/core/src/main/java/com/cloud/agent/api/ListHostUsbDeviceCommand.java new file mode 100644 index 000000000000..b7165d6f6165 --- /dev/null +++ b/core/src/main/java/com/cloud/agent/api/ListHostUsbDeviceCommand.java @@ -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 com.cloud.agent.api; + +import java.util.List; + +public class ListHostUsbDeviceCommand extends Command { + + private List hostDevicesName; + private List hostDevicesText; + private Long id; + + public ListHostUsbDeviceCommand() { + } + + public ListHostUsbDeviceCommand(Long id) { + super(); + this.id = id; + } + + @Override + public boolean executeInSequence() { + return false; + } + + public List getHostDevicesName() { + return hostDevicesName; + } + + public List getHostDevicesText() { + return hostDevicesText; + } + + public Long getId() { + return id; + } + + public void setHostDevicesName(List hostDevicesName) { + this.hostDevicesName = hostDevicesName; + } +} diff --git a/core/src/main/java/com/cloud/agent/api/UpdateHostUsbDeviceAnswer.java b/core/src/main/java/com/cloud/agent/api/UpdateHostUsbDeviceAnswer.java new file mode 100644 index 000000000000..ab1710a591f6 --- /dev/null +++ b/core/src/main/java/com/cloud/agent/api/UpdateHostUsbDeviceAnswer.java @@ -0,0 +1,55 @@ +/* + * 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 UpdateHostUsbDeviceAnswer extends Answer { + private boolean successMessage; + private String vmName; + private String xmlConfig; + private boolean isAttach; + + public UpdateHostUsbDeviceAnswer() { + super(); + } + + public UpdateHostUsbDeviceAnswer(boolean successMessage, String vmName, String xmlConfig, boolean isAttach) { + super(); + this.successMessage = successMessage; + this.vmName = vmName; + this.xmlConfig = xmlConfig; + this.isAttach = isAttach; + } + + public String getVmName() { + return vmName; + } + + public String getXmlConfig() { + return xmlConfig; + } + + public boolean getIsAttach() { + return isAttach; + } + + public boolean isSuccessMessage() { + return successMessage; + } +} diff --git a/core/src/main/java/com/cloud/agent/api/UpdateHostUsbDeviceCommand.java b/core/src/main/java/com/cloud/agent/api/UpdateHostUsbDeviceCommand.java new file mode 100644 index 000000000000..1217a79b0b0a --- /dev/null +++ b/core/src/main/java/com/cloud/agent/api/UpdateHostUsbDeviceCommand.java @@ -0,0 +1,65 @@ +/* + * 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 UpdateHostUsbDeviceCommand extends Command { + + private String vmName; + private String xmlConfig; + private boolean isAttach; + + public UpdateHostUsbDeviceCommand() { + } + + public UpdateHostUsbDeviceCommand(String vmName, String xmlConfig, boolean isAttach) { + this.vmName = vmName; + this.xmlConfig = xmlConfig; + this.isAttach = isAttach; + } + + @Override + public boolean executeInSequence() { + return false; + } + + public String getVmName() { + return vmName; + } + + public String getXmlConfig() { + return xmlConfig; + } + + public boolean getIsAttach() { + return isAttach; + } + + public void setVmName(String vmName) { + this.vmName = vmName; + } + + public void setXmlConfig(String xmlConfig) { + this.xmlConfig = xmlConfig; + } + + public void setIsAttach(boolean isAttach) { + this.isAttach = isAttach; + } +} diff --git a/core/src/main/java/com/cloud/resource/ServerResourceBase.java b/core/src/main/java/com/cloud/resource/ServerResourceBase.java index 3517c7b62d24..f2085449e486 100644 --- a/core/src/main/java/com/cloud/resource/ServerResourceBase.java +++ b/core/src/main/java/com/cloud/resource/ServerResourceBase.java @@ -45,6 +45,8 @@ import org.apache.commons.collections.CollectionUtils; import org.apache.commons.lang3.StringUtils; import org.apache.logging.log4j.Logger; +// import org.json.JSONArray; +// import org.json.JSONObject; import org.apache.logging.log4j.LogManager; import com.cloud.agent.IAgentControl; @@ -55,6 +57,9 @@ import com.cloud.utils.script.OutputInterpreter; import com.cloud.utils.script.Script; import com.cloud.agent.api.ListHostDeviceAnswer; +// import com.cloud.agent.api.ListHostLunDeviceAnswer; +// import com.cloud.agent.api.ListHostUsbDeviceAnswer; +// import com.cloud.agent.api.ListHostLunDeviceCommand; public abstract class ServerResourceBase implements ServerResource { protected Logger logger = LogManager.getLogger(getClass()); @@ -165,6 +170,7 @@ protected boolean isValidNicToUseAsPrivateNic(NetworkInterface nic) { protected Answer listHostDevices() { List hostDevicesText = new ArrayList<>(); + List hostDevicesNames = new ArrayList<>(); Script listCommand = new Script("lspci"); OutputInterpreter.AllLinesParser parser = new OutputInterpreter.AllLinesParser(); String result = listCommand.execute(parser); @@ -178,7 +184,7 @@ protected Answer listHostDevices() { } } } - return new ListHostDeviceAnswer(true, hostDevicesText); + return new ListHostDeviceAnswer(true, hostDevicesNames, hostDevicesText); } protected Answer createImageRbd(String poolUuid, String skey, String authUserName, String host, String names, long sizes, String poolPath) { @@ -512,4 +518,45 @@ public boolean start() { public boolean stop() { return true; } + + // protected Answer updateHostUsbDevices(Command command, String vmName, String xmlConfig, boolean isAttach) { + // try { + // // 임시 XML 파일 생성 + // String tempXmlPath = "/tmp/usb_device_" + System.currentTimeMillis() + ".xml"; + // try (PrintWriter writer = new PrintWriter(tempXmlPath)) { + // writer.write(xmlConfig); + // } + // logger.info("Generated temporary XML file: {}", tempXmlPath); + // // virsh 명령어 실행 + // Script virshCmd = new Script("virsh"); + // if (isAttach) { + // virshCmd.add("attach-device", vmName, tempXmlPath); + // } else { + // virshCmd.add("detach-device", vmName, tempXmlPath); + // } + + // String result = virshCmd.execute(); + + // // 임시 파일 삭제 + // File tempFile = new File(tempXmlPath); + // if (tempFile.exists() && !tempFile.delete()) { + // logger.warn("Failed to delete temporary file: {}", tempXmlPath); + // } + + // if (result != null) { + // String action = isAttach ? "attach" : "detach"; + // logger.error("Failed to {} USB device: {}", action, result); + // return new Answer(command, false, "Failed to " + action + " USB device: " + result); + // } + + // String action = isAttach ? "attached to" : "detached from"; + // logger.info("Successfully {} USB device {} VM {}", action, tempXmlPath, vmName); + // return new Answer(command, true, null); + + // } catch (Exception e) { + // String action = isAttach ? "attaching" : "detaching"; + // logger.error("Error {} USB device: {}", action, e.getMessage(), e); + // return new Answer(command, false, "Error " + action + " USB device: " + e.getMessage()); + // } + // } } \ No newline at end of file diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java index eb5f381b5eda..4c4535372987 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/LibvirtComputingResource.java @@ -113,6 +113,9 @@ import com.cloud.agent.api.Command; import com.cloud.agent.api.HostVmStateReportEntry; import com.cloud.agent.api.ListHostDeviceCommand; +// import com.cloud.agent.api.ListHostLunDeviceCommand; +// import com.cloud.agent.api.ListHostUsbDeviceCommand; +// import com.cloud.agent.api.UpdateHostUsbDeviceCommand; import com.cloud.agent.api.PingCommand; import com.cloud.agent.api.PingRoutingCommand; import com.cloud.agent.api.PingRoutingWithNwGroupsCommand; @@ -5512,6 +5515,31 @@ public Answer listHostDevices(ListHostDeviceCommand command) { } } + // public Answer listHostUsbDevices(ListHostUsbDeviceCommand command) { + // logger.info("listusb: " + command.getId()); + // if (command.getId() != null) { + // // 상위 클래스의 메서드를 호출 + // return super.listHostUsbDevices(command); + // } else { + // throw new IllegalArgumentException("Host ID cannot be null"); + // } + // } + + // public Answer listHostLunDevices(ListHostLunDeviceCommand command) { + // logger.info("listlun: " + command.getId()); + // if (command.getId() != null) { + // // 상위 클래스의 메서드를 호출 + // return super.listHostLunDevices(command); + // } else { + // throw new IllegalArgumentException("Host ID cannot be null"); + // } + // } + // public Answer updateHostUsbDevices(UpdateHostUsbDeviceCommand command, String vmName, String xmlConfig, boolean isAttach) { + // logger.info("Received USB device update command - VM: {}, isAttach: {}, xmlConfig: {}", + // vmName, isAttach, xmlConfig); + // return super.updateHostUsbDevices(command, vmName, xmlConfig, isAttach); + // } + public Answer listFilesAtPath(ListDataStoreObjectsCommand command) { DataStoreTO store = command.getStore(); if(command.getPoolType().equals("RBD")) { diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtlistHostLunDevicesCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtlistHostLunDevicesCommandWrapper.java new file mode 100644 index 000000000000..b9a334d57928 --- /dev/null +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtlistHostLunDevicesCommandWrapper.java @@ -0,0 +1,37 @@ +// +// 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.hypervisor.kvm.resource.wrapper; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.ListHostLunDeviceCommand; +import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource; +import com.cloud.resource.CommandWrapper; +import com.cloud.resource.ResourceWrapper; + +@ResourceWrapper(handles = ListHostLunDeviceCommand.class) +public final class LibvirtlistHostLunDevicesCommandWrapper + extends CommandWrapper { + @Override + public Answer execute(final ListHostLunDeviceCommand command, + final LibvirtComputingResource libvirtComputingResource) { + return null; + // libvirtComputingResource.listHostLunDevices(command); + } +} diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtlistHostUsbDevicesCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtlistHostUsbDevicesCommandWrapper.java new file mode 100644 index 000000000000..608e493488ba --- /dev/null +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtlistHostUsbDevicesCommandWrapper.java @@ -0,0 +1,37 @@ +// +// 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.hypervisor.kvm.resource.wrapper; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.ListHostUsbDeviceCommand; +import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource; +import com.cloud.resource.CommandWrapper; +import com.cloud.resource.ResourceWrapper; + +@ResourceWrapper(handles = ListHostUsbDeviceCommand.class) +public final class LibvirtlistHostUsbDevicesCommandWrapper + extends CommandWrapper { + @Override + public Answer execute(final ListHostUsbDeviceCommand command, + final LibvirtComputingResource libvirtComputingResource) { + return null; + // libvirtComputingResource.listHostUsbDevices(command); + } +} diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtupdateHostUsbDevicesCommandWrapper.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtupdateHostUsbDevicesCommandWrapper.java new file mode 100644 index 000000000000..351a000a7289 --- /dev/null +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/wrapper/LibvirtupdateHostUsbDevicesCommandWrapper.java @@ -0,0 +1,37 @@ +// +// 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.hypervisor.kvm.resource.wrapper; + +import com.cloud.agent.api.Answer; +import com.cloud.agent.api.UpdateHostUsbDeviceCommand; +import com.cloud.hypervisor.kvm.resource.LibvirtComputingResource; +import com.cloud.resource.CommandWrapper; +import com.cloud.resource.ResourceWrapper; + +@ResourceWrapper(handles = UpdateHostUsbDeviceCommand.class) +public final class LibvirtupdateHostUsbDevicesCommandWrapper + extends CommandWrapper { + @Override + public Answer execute(final UpdateHostUsbDeviceCommand command, + final LibvirtComputingResource libvirtComputingResource) { + return null; + // libvirtComputingResource.updateHostUsbDevices(command); + } +} diff --git a/server/src/main/java/com/cloud/server/ManagementServerImpl.java b/server/src/main/java/com/cloud/server/ManagementServerImpl.java index 652196c94373..2a9790f57fd9 100644 --- a/server/src/main/java/com/cloud/server/ManagementServerImpl.java +++ b/server/src/main/java/com/cloud/server/ManagementServerImpl.java @@ -19,7 +19,9 @@ package com.cloud.server; import java.io.BufferedReader; +// import java.io.File; import java.io.InputStreamReader; +// import java.io.PrintWriter; import java.lang.reflect.Field; import java.net.SocketTimeoutException; import java.net.URL; @@ -33,6 +35,7 @@ import java.util.Comparator; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Map; @@ -177,6 +180,11 @@ import org.apache.cloudstack.api.command.admin.outofbandmanagement.IssueOutOfBandManagementPowerActionCmd; import org.apache.cloudstack.api.command.admin.outofbandmanagement.LicenseCheckCmd; import org.apache.cloudstack.api.command.admin.outofbandmanagement.ListHostDevicesCmd; +// import org.apache.cloudstack.api.command.admin.outofbandmanagement.ListHostLunDevicesCmd; +// import org.apache.cloudstack.api.command.admin.outofbandmanagement.ListHostUsbDevicesCmd; +import org.apache.cloudstack.api.command.admin.outofbandmanagement.UpdateHostDevicesCmd; +// import org.apache.cloudstack.api.command.admin.outofbandmanagement.UpdateHostLunDevicesCmd; +// import org.apac import org.apache.cloudstack.api.command.admin.pod.CreatePodCmd; import org.apache.cloudstack.api.command.admin.pod.DeletePodCmd; import org.apache.cloudstack.api.command.admin.pod.ListPodsByCmd; @@ -614,7 +622,12 @@ import org.apache.cloudstack.api.command.user.zone.ListZonesCmd; import org.apache.cloudstack.api.response.LicenseCheckerResponse; import org.apache.cloudstack.api.response.ListHostDevicesResponse; +// import org.apache.cloudstack.api.response.ListHostLunDevicesResponse; +// import org.apache.cloudstack.api.response.ListHostUsbDevicesResponse; import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.UpdateHostDevicesResponse; +// import org.apache.cloudstack.api.response.UpdateHostLunDevicesResponse; +// import org.apache.cloudstack.api.response.UpdateHostUsbDevicesResponse; import org.apache.cloudstack.auth.UserAuthenticator; import org.apache.cloudstack.auth.UserTwoFactorAuthenticator; import org.apache.cloudstack.config.ApiServiceConfiguration; @@ -670,8 +683,15 @@ import com.cloud.agent.api.GetVncPortCommand; import com.cloud.agent.api.ListHostDeviceAnswer; import com.cloud.agent.api.ListHostDeviceCommand; +// import com.cloud.agent.api.ListHostLunDeviceAnswer; +// import com.cloud.agent.api.ListHostLunDeviceCommand; +// import com.cloud.agent.api.ListHostUsbDeviceAnswer; +// import com.cloud.agent.api.ListHostUsbDeviceCommand; import com.cloud.agent.api.PatchSystemVmAnswer; import com.cloud.agent.api.PatchSystemVmCommand; +// import com.cloud.agent.api.PatchSystemVmCommand; +// import com.cloud.agent.api.UpdateHostUsbDeviceAnswer; +// import com.cloud.agent.api.UpdateHostUsbDeviceCommand; import com.cloud.agent.api.proxy.AllowConsoleAccessCommand; import com.cloud.agent.api.routing.NetworkElementCommand; import com.cloud.agent.manager.Commands; @@ -870,6 +890,7 @@ + public class ManagementServerImpl extends ManagerBase implements ManagementServer, Configurable { protected StateMachine2 _stateMachine; @@ -1057,6 +1078,12 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe @Inject private HAConfigDao haConfigDao; + @Inject + private HostDetailsDao _hostDetailsDao; + + @Inject + private UserVmDetailsDao _vmDetailsDao; + private LockControllerListener _lockControllerListener; private final ScheduledExecutorService _eventExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("EventChecker")); private final ScheduledExecutorService _alertExecutor = Executors.newScheduledThreadPool(1, new NamedThreadFactory("AlertChecker")); @@ -2170,6 +2197,627 @@ public Pair, Integer> searchForPods(final ListPodsByCmd cmd) return new Pair<>(result.first(), result.second()); } + + // @Override + // public ListResponse listHostUsbDevices(ListHostUsbDevicesCmd cmd) { + // Long id = cmd.getId(); + // HostVO hostVO = _hostDao.findById(id); + // if (hostVO == null) { + // throw new CloudRuntimeException("Host not found with ID: " + id); + // } + + // ListHostUsbDeviceCommand usbCmd = new ListHostUsbDeviceCommand(id); + // Answer answer; + // try { + // answer = _agentMgr.send(hostVO.getId(), usbCmd); + // } catch (Exception e) { + // String errorMsg = "Error sending ListHostUsbDeviceCommand: " + e.getMessage(); + // logger.error(errorMsg, e); + // throw new CloudRuntimeException(errorMsg, e); + // } + + // if (answer == null) { + // throw new CloudRuntimeException("Answer is null"); + // } + // if (!answer.getResult()) { + // String errorDetails = (answer.getDetails() != null) ? answer.getDetails() + // : "No additional details available"; + // String errorMsg = "Answer result is false. Details: " + errorDetails; + // logger.error(errorMsg); + // throw new CloudRuntimeException(errorMsg); + // } + // if (!(answer instanceof ListHostUsbDeviceAnswer)) { + // throw new CloudRuntimeException("Answer is not an instance of listHostUsbDeviceAnswer"); + // } + + // ListHostUsbDeviceAnswer usbAnswer = (ListHostUsbDeviceAnswer) answer; + // if (!usbAnswer.isSuccessMessage()) { + // throw new IllegalArgumentException("Failed to list VM USB objects."); + // } + + // List responses = new ArrayList<>(); + // ListResponse listResponse = new ListResponse<>(); + + // List hostDevicesTexts = usbAnswer.getHostDevicesTexts(); + + // List hostDevicesNames = new ArrayList<>(); + // List pciDescriptions = new ArrayList<>(); + + // for (String hostDevicesText : hostDevicesTexts) { + // String[] parts = hostDevicesText.split(": ", 2); + // if (parts.length == 2) { + // hostDevicesNames.add(parts[0].trim()); + // pciDescriptions.add(parts[1].trim()); + // } else { + // logger.warn("Unexpected PCI info format: " + hostDevicesText); + // } + // } + + // ListHostUsbDevicesResponse response = new ListHostUsbDevicesResponse(); + // response.setHostDevicesNames(hostDevicesNames); + // response.setHostDevicesTexts(pciDescriptions); + + // // VM 할당 정보 확인 및 업데이트 + // Map vmAllocations = new HashMap<>(); + // for (String deviceName : hostDevicesNames) { + // // 현재 할당 상태 확인 + // String currentAllocation = getDeviceAllocation(id, deviceName); + + // if (currentAllocation != null) { + // // 이미 할당된 경우에만 맵에 추가 + // vmAllocations.put(deviceName, currentAllocation); + // } + // } + // response.setVmAllocations(vmAllocations); + + // responses.add(response); + // listResponse.setResponses(responses); + // return listResponse; + // } + + // @Override + // public ListResponse listHostLunDevices(ListHostLunDevicesCmd cmd) { + // Long id = cmd.getId(); + // HostVO hostVO = _hostDao.findById(id); + // if (hostVO == null) { + // throw new CloudRuntimeException("Host not found with ID: " + id); + // } + + // ListHostLunDeviceCommand lunCmd = new ListHostLunDeviceCommand(id); + // Answer answer; + // try { + // answer = _agentMgr.send(hostVO.getId(), lunCmd); + // } catch (Exception e) { + // String errorMsg = "Error sending ListHostLunDeviceCommand: " + e.getMessage(); + // logger.error(errorMsg, e); + // throw new CloudRuntimeException(errorMsg, e); + // } + + // validateAnswer(answer); + // ListHostLunDeviceAnswer lunAnswer = (ListHostLunDeviceAnswer) answer; + + // ListResponse listResponse = new ListResponse<>(); + // List responses = new ArrayList<>(); + + // ListHostLunDevicesResponse response = createResponse(lunAnswer, id); + // responses.add(response); + + // listResponse.setResponses(responses); + // return listResponse; + // } + + // private void validateAnswer(Answer answer) { + // if (answer == null) { + // throw new CloudRuntimeException("Answer is null"); + // } + // if (!answer.getResult()) { + // String errorDetails = answer.getDetails() != null ? answer.getDetails() + // : "No additional details available"; + // throw new CloudRuntimeException("Answer result is false. Details: " + errorDetails); + // } + // if (!(answer instanceof ListHostLunDeviceAnswer)) { + // throw new CloudRuntimeException("Answer is not an instance of ListHostLunDeviceAnswer"); + // } + // } + + // private ListHostLunDevicesResponse createResponse(ListHostLunDeviceAnswer lunAnswer, Long hostId) { + // ListHostLunDevicesResponse response = new ListHostLunDevicesResponse(); + + // List deviceNames = new ArrayList<>(); + // List deviceDescriptions = new ArrayList<>(); + // List hasPartitions = lunAnswer.getHasPartitions(); + + // for (int i = 0; i < lunAnswer.getHostDevicesTexts().size(); i++) { + // String deviceText = lunAnswer.getHostDevicesTexts().get(i); + // String deviceName = lunAnswer.getHostDevicesNames().get(i); + // boolean hasPartition = hasPartitions.get(i); + + // deviceNames.add(deviceName); + // deviceDescriptions.add(deviceText); + // response.addPartitionInfo(deviceName, hasPartition); + // } + + // response.setHostDevicesNames(deviceNames); + // response.setHostDevicesTexts(deviceDescriptions); + + // Map vmAllocations = new HashMap<>(); + // for (String deviceName : deviceNames) { + // String allocation = getDeviceAllocation(hostId, deviceName); + // if (allocation != null) { + // vmAllocations.put(deviceName, allocation); + // } + // } + // response.setVmAllocations(vmAllocations); + + // return response; + // } + + @Override + public ListResponse listHostDevices(ListHostDevicesCmd cmd) { + Long id = cmd.getId(); + HostVO hostVO = _hostDao.findById(id); + if (hostVO == null) { + throw new CloudRuntimeException("Host not found with ID: " + id); + } + + ListHostDeviceCommand pciCmd = new ListHostDeviceCommand(id); + Answer answer; + try { + answer = _agentMgr.send(hostVO.getId(), pciCmd); + } catch (Exception e) { + String errorMsg = "Error sending ListHostDevicesCommand: " + e.getMessage(); + logger.error(errorMsg, e); + throw new CloudRuntimeException(errorMsg, e); + } + + if (answer == null) { + throw new CloudRuntimeException("Answer is null"); + } + if (!answer.getResult()) { + String errorDetails = (answer.getDetails() != null) ? answer.getDetails() + : "No additional details available"; + String errorMsg = "Answer result is false. Details: " + errorDetails; + logger.error(errorMsg); + throw new CloudRuntimeException(errorMsg); + } + if (!(answer instanceof ListHostDeviceAnswer)) { + throw new CloudRuntimeException("Answer is not an instance of listHostDeviceAnswer"); + } + + ListHostDeviceAnswer pciAnswer = (ListHostDeviceAnswer) answer; + if (!pciAnswer.isSuccessMessage()) { + throw new IllegalArgumentException("Failed to list VM PCI objects."); + } + + List responses = new ArrayList<>(); + ListResponse listResponse = new ListResponse<>(); + + List hostDevicesTexts = pciAnswer.getHostDevicesTexts(); + + List hostDevicesNames = new ArrayList<>(); + List pciDescriptions = new ArrayList<>(); + + for (String hostDevicesText : hostDevicesTexts) { + String[] parts = hostDevicesText.split(": ", 2); + if (parts.length == 2) { + hostDevicesNames.add(parts[0].trim()); + pciDescriptions.add(parts[1].trim()); + } else { + logger.warn("Unexpected PCI info format: " + hostDevicesText); + } + } + + ListHostDevicesResponse response = new ListHostDevicesResponse(); + response.setHostDevicesNames(hostDevicesNames); + response.setHostDevicesTexts(pciDescriptions); + + // VM 할당 정보 확인 및 업데이트 + Map vmAllocations = new HashMap<>(); + for (String deviceName : hostDevicesNames) { + // 현재 할당 상태 확인 + String currentAllocation = getDeviceAllocation(id, deviceName); + + if (currentAllocation != null) { + // 이미 할당된 경우에만 맵에 추가 + vmAllocations.put(deviceName, currentAllocation); + } + } + response.setVmAllocations(vmAllocations); + + responses.add(response); + listResponse.setResponses(responses); + return listResponse; + } + + // VM에 디바이스가 할당될 때 호출되는 메서드 + @Override + public ListResponse updateHostDevices(UpdateHostDevicesCmd cmd) { + Long hostId = cmd.getHostId(); + String hostDeviceName = cmd.getHostDeviceName(); + Long vmId = cmd.getVirtualMachineId(); + + // 호스트 존재 여부 확인 + HostVO hostVO = _hostDao.findById(hostId); + if (hostVO == null) { + throw new CloudRuntimeException("Host not found with ID: " + hostId); + } + + // VM 존재 여부 확인 (vmId가 null이 아닌 경우) + VMInstanceVO vmInstance = null; + if (vmId != null) { + vmInstance = _vmInstanceDao.findById(vmId); + if (vmInstance == null) { + throw new CloudRuntimeException("VM not found with ID: " + vmId); + } + } + + logger.info("Updating host device allocation - hostId: {}, hostDeviceName: {}, virtualMachineId: {}", + hostId, hostDeviceName, vmId); + + try { + DetailVO currentAllocation = _hostDetailsDao.findDetail(hostId, hostDeviceName); + + if (vmId == null) { + // 디바이스 할당 해제 + if (currentAllocation != null) { + String currentVmId = currentAllocation.getValue(); + VMInstanceVO vm = _vmInstanceDao.findById(Long.parseLong(currentVmId)); + if (vm != null) { + // 해당 VM의 모든 extraconfig 항목 조회 + List existingConfigs = _vmDetailsDao.listDetails(vm.getId()); + + // 현재 디바이스의 설정 찾기 및 제거 + for (UserVmDetailVO detail : existingConfigs) { + if (detail.getName().startsWith("extraconfig-") && + detail.getValue().contains(hostDeviceName)) { + _vmDetailsDao.removeDetail(vm.getId(), detail.getName()); + logger.info("Successfully removed device configuration {} from VM {}", + detail.getName(), vm.getInstanceName()); + break; + } + } + } + // DB에서 해당 디바이스 레코드 삭제 + _hostDetailsDao.remove(currentAllocation.getId()); + logger.info("Successfully removed device {} allocation from host {}", hostDeviceName, hostId); + } + } else { + // 새로운 할당 + if (currentAllocation != null) { + String currentVmId = currentAllocation.getValue(); + VMInstanceVO vm = _vmInstanceDao.findById(Long.parseLong(currentVmId)); + throw new CloudRuntimeException("Device " + hostDeviceName + " is already allocated to VM: " + + (vm != null ? vm.getInstanceName() : currentVmId)); + } + + // 다음 사용 가능한 extraconfig 번호 찾기 + List existingConfigs = _vmDetailsDao.listDetails(vmInstance.getId()); + int nextConfigNum = 1; + Set usedNums = new HashSet<>(); + + for (UserVmDetailVO detail : existingConfigs) { + if (detail.getName().startsWith("extraconfig-")) { + try { + int num = Integer.parseInt(detail.getName().split("-")[1]); + usedNums.add(num); + } catch (NumberFormatException e) { + logger.warn("Invalid extraconfig number format: {}", detail.getName()); + } + } + } + + while (usedNums.contains(nextConfigNum)) { + nextConfigNum++; + } + logger.info("Successfully added device configuration to VM {} with config number {}", + vmInstance.getInstanceName(), nextConfigNum); + + // DB에 할당 정보 저장 + Map details = new HashMap<>(); + details.put(hostDeviceName, vmId.toString()); + _hostDetailsDao.persist(hostId, details); + logger.info("Successfully allocated device {} to VM {} on host {}", + hostDeviceName, vmId, hostId); + } + } catch (Exception e) { + logger.error("Error during device allocation/deallocation - hostDeviceName: {}, error: {}", + hostDeviceName, e.getMessage(), e); + throw new CloudRuntimeException("Failed to update device allocation: " + e.getMessage(), e); + } + + // 응답 생성 + ListResponse response = new ListResponse<>(); + List responses = new ArrayList<>(); + UpdateHostDevicesResponse deviceResponse = new UpdateHostDevicesResponse(); + + DetailVO allocation = _hostDetailsDao.findDetail(hostId, hostDeviceName); + deviceResponse.setHostDeviceName(hostDeviceName); + deviceResponse.setVirtualMachineId(allocation != null ? allocation.getValue() : null); + deviceResponse.setAllocated(allocation != null && allocation.getValue() != null); + + responses.add(deviceResponse); + response.setResponses(responses); + + return response; + } + + // PCI 디바이스의 VM 할당 상태 조회 + public String getDeviceAllocation(Long hostId, String deviceName) { + DetailVO vmAllocationDetail = _hostDetailsDao.findDetail(hostId, deviceName); + return vmAllocationDetail != null ? vmAllocationDetail.getValue() : null; + } + + // VM에 디바이스가 할당될 때 호출되는 메서드 + // @Override + // public ListResponse updateHostUsbDevices(UpdateHostUsbDevicesCmd cmd) { + // Long hostId = cmd.getHostId(); + // String hostDeviceName = cmd.getHostDeviceName(); + // Long vmId = cmd.getVirtualMachineId(); + // String xmlConfig = cmd.getXmlConfig(); + + // // 호스트 존재 여부 확인 + // HostVO hostVO = _hostDao.findById(hostId); + // if (hostVO == null) { + // throw new CloudRuntimeException("Host not found with ID: " + hostId); + // } + + // // VM 존재 여부 확인 (vmId가 null이 아닌 경우) + // VMInstanceVO vmInstance = null; + // if (vmId != null) { + // vmInstance = _vmInstanceDao.findById(vmId); + // if (vmInstance == null) { + // throw new CloudRuntimeException("VM not found with ID: " + vmId); + // } + // } + + // logger.info("Updating host device allocation - hostId: {}, hostDeviceName: {}, virtualMachineId: {}", + // hostId, hostDeviceName, vmId); + + // try { + // DetailVO currentAllocation = _hostDetailsDao.findDetail(hostId, hostDeviceName); + // String vmInternalName = null; + // boolean isAttach = (vmId != null); + + // if (!isAttach) { + // // 디바이스 할당 해제 + // String currentVmId = cmd.getCurrentVmId(); + // if (currentAllocation != null && currentVmId != null) { + // // 현재 할당된 VM이 요청된 VM과 일치하는지 확인 + // if (!currentVmId.equals(currentAllocation.getValue())) { + // throw new CloudRuntimeException("Device is allocated to a different VM"); + // } + // VMInstanceVO vm = _vmInstanceDao.findById(Long.parseLong(currentVmId)); + // if (vm != null) { + // vmInternalName = vm.getInstanceName(); + // } + // } + // } else { + // // 새로운 할당 + // if (currentAllocation != null) { + // throw new CloudRuntimeException("Device is already allocated to VM: " + currentAllocation.getValue()); + // } + // vmInternalName = vmInstance.getInstanceName(); + // } + + // if (vmInternalName == null) { + // throw new CloudRuntimeException("Unable to get VM instance name"); + // } + + // // 호스트에 명령 전송 + // UpdateHostUsbDeviceCommand usbCmd = new UpdateHostUsbDeviceCommand(vmInternalName, xmlConfig, isAttach); + // Answer answer; + // try { + // answer = _agentMgr.send(hostVO.getId(), usbCmd); + // } catch (Exception e) { + // String errorMsg = "Error sending UpdateHostUsbDeviceCommand: " + e.getMessage(); + // logger.error(errorMsg, e); + // throw new CloudRuntimeException(errorMsg, e); + // } + + // if (answer == null) { + // throw new CloudRuntimeException("Answer is null"); + // } + // if (!answer.getResult()) { + // String errorDetails = (answer.getDetails() != null) ? + // answer.getDetails() : "No additional details available"; + // throw new CloudRuntimeException("Failed to update USB device. Details: " + errorDetails); + // } + // if (!(answer instanceof UpdateHostUsbDeviceAnswer)) { + // throw new CloudRuntimeException("Answer is not an instance of UpdateHostUsbDeviceAnswer"); + // } + + // UpdateHostUsbDeviceAnswer usbAnswer = (UpdateHostUsbDeviceAnswer) answer; + // if (!usbAnswer.isSuccessMessage()) { + // throw new CloudRuntimeException("Failed to update USB device for VM: " + usbAnswer.getVmName()); + // } + + // // DB 업데이트 + // if (!isAttach) { + // // 할당 해제 + // if (currentAllocation != null) { + // _hostDetailsDao.remove(currentAllocation.getId()); + // } + // } else { + // // 새로운 할당 + // DetailVO detail = new DetailVO(hostId, hostDeviceName, vmId.toString()); + // _hostDetailsDao.persist(detail); + // } + + // // 응답 생성 + // ListResponse response = new ListResponse<>(); + // List responses = new ArrayList<>(); + // UpdateHostUsbDevicesResponse deviceResponse = new UpdateHostUsbDevicesResponse(); + + // DetailVO allocation = _hostDetailsDao.findDetail(hostId, hostDeviceName); + // deviceResponse.setHostDeviceName(hostDeviceName); + // deviceResponse.setVirtualMachineId(allocation != null ? allocation.getValue() : null); + // deviceResponse.setAllocated(allocation != null); + + // responses.add(deviceResponse); + // response.setResponses(responses); + + // return response; + + // } catch (Exception e) { + // logger.error("Error during USB device allocation/deallocation - hostDeviceName: {}, error: {}", + // hostDeviceName, e.getMessage(), e); + // throw new CloudRuntimeException("Failed to update USB device allocation: " + e.getMessage(), e); + // } + // } + // VM에 디바이스가 할당될 때 호출되는 메서드 + // @Override + // public ListResponse updateHostLunDevices(UpdateHostLunDevicesCmd cmd) { + // Long hostId = cmd.getHostId(); + // String hostDeviceName = cmd.getHostDeviceName(); + // Long vmId = cmd.getVirtualMachineId(); + // String xmlConfig = cmd.getXmlConfig(); + + // // 호스트 존재 여부 확인 + // HostVO hostVO = _hostDao.findById(hostId); + // if (hostVO == null) { + // throw new CloudRuntimeException("Host not found with ID: " + hostId); + // } + + // // VM 존재 여부 확인 (vmId가 null이 아닌 경우) + // VMInstanceVO vmInstance = null; + // if (vmId != null) { + // vmInstance = _vmInstanceDao.findById(vmId); + // if (vmInstance == null) { + // throw new CloudRuntimeException("VM not found with ID: " + vmId); + // } + // } + + // logger.info("Updating host device allocation - hostId: {}, hostDeviceName: {}, virtualMachineId: {}", + // hostId, hostDeviceName, vmId); + + // try { + // DetailVO currentAllocation = _hostDetailsDao.findDetail(hostId, hostDeviceName); + + // if (vmId == null) { + // // 디바이스 할당 해제 + // if (currentAllocation != null) { + // Set allocatedVmIds = new HashSet<>(Arrays.asList(currentAllocation.getValue().split(","))); + // String currentVmId = cmd.getCurrentVmId(); + + // if (currentVmId != null && allocatedVmIds.contains(currentVmId)) { + // VMInstanceVO vm = _vmInstanceDao.findById(Long.parseLong(currentVmId)); + // if (vm != null) { + // String vmInternalName = vm.getInstanceName(); + + // // LUN 디바이스 분리 로직 + // String tempXmlPath = "/tmp/lun_device_" + hostDeviceName.replace("/", "_") + "_" + + // currentVmId + "_" + System.currentTimeMillis() + ".xml"; + // try { + // try (PrintWriter writer = new PrintWriter(tempXmlPath)) { + // writer.write(xmlConfig); + // } + + // Script detachCmd = new Script("/usr/bin/virsh"); + // detachCmd.add("detach-device", vmInternalName, tempXmlPath); + // String result = detachCmd.execute(); + + // File tempFile = new File(tempXmlPath); + // if (tempFile.exists() && !tempFile.delete()) { + // logger.warn("Failed to delete temporary file: {}", tempXmlPath); + // } + + // if (result != null) { + // throw new CloudRuntimeException("Failed to detach LUN device: " + result); + // } + // logger.info("Successfully detached LUN device from VM {}", vmInternalName); + // } catch (Exception e) { + // logger.error("Error detaching LUN device: " + e.getMessage(), e); + // throw new CloudRuntimeException("Failed to detach LUN device: " + e.getMessage()); + // } + // } + + // // VM ID 제거 후 업데이트 + // allocatedVmIds.remove(currentVmId); + // if (allocatedVmIds.isEmpty()) { + // _hostDetailsDao.remove(currentAllocation.getId()); + // } else { + // Map details = new HashMap<>(); + // details.put(hostDeviceName, String.join(",", allocatedVmIds)); + // _hostDetailsDao.persist(hostId, details); + // } + // } + // } + // } else { + // // 새로운 할당 + // if (vmInstance == null) { + // throw new CloudRuntimeException("VM instance cannot be null for device allocation"); + // } + + // Set allocatedVmIds = new HashSet<>(); + // if (currentAllocation != null) { + // allocatedVmIds.addAll(Arrays.asList(currentAllocation.getValue().split(","))); + // } + + // if (allocatedVmIds.contains(vmId.toString())) { + // throw new CloudRuntimeException("VM " + vmInstance.getInstanceName() + " is already allocated to this device"); + // } + + // String vmInternalName = vmInstance.getInstanceName(); + // if (vmInternalName == null) { + // throw new CloudRuntimeException("Unable to get VM instance name"); + // } + + // // LUN 디바이스 연결 로직 + // String tempXmlPath = "/tmp/lun_device_" + hostDeviceName.replace("/", "_") + "_" + + // vmId + "_" + System.currentTimeMillis() + ".xml"; + // try { + // try (PrintWriter writer = new PrintWriter(tempXmlPath)) { + // writer.write(xmlConfig); + // } + + // Script attachCmd = new Script("/usr/bin/virsh"); + // attachCmd.add("attach-device", vmInternalName, tempXmlPath); + // String result = attachCmd.execute(); + + // File tempFile = new File(tempXmlPath); + // if (tempFile.exists() && !tempFile.delete()) { + // logger.warn("Failed to delete temporary file: {}", tempXmlPath); + // } + + // if (result != null) { + // throw new CloudRuntimeException("Failed to attach LUN device: " + result); + // } + // logger.info("Successfully attached LUN device to VM {}", vmInternalName); + // } catch (Exception e) { + // logger.error("Error attaching LUN device: " + e.getMessage(), e); + // throw new CloudRuntimeException("Failed to attach LUN device: " + e.getMessage()); + // } + + // // 새로운 VM ID 추가 + // allocatedVmIds.add(vmId.toString()); + + // // DB에 할당 정보 저장 + // Map details = new HashMap<>(); + // details.put(hostDeviceName, String.join(",", allocatedVmIds)); + // _hostDetailsDao.persist(hostId, details); + // } + + // // 응답 생성 + // ListResponse response = new ListResponse<>(); + // List responses = new ArrayList<>(); + // UpdateHostLunDevicesResponse deviceResponse = new UpdateHostLunDevicesResponse(); + + // DetailVO allocation = _hostDetailsDao.findDetail(hostId, hostDeviceName); + // deviceResponse.setHostDeviceName(hostDeviceName); + // deviceResponse.setVirtualMachineId(allocation != null ? allocation.getValue() : null); + // deviceResponse.setAllocated(allocation != null && allocation.getValue() != null); + + // responses.add(deviceResponse); + // response.setResponses(responses); + + // return response; + // } catch (Exception e) { + // logger.error("Error during LUN device allocation/deallocation - hostDeviceName: {}, error: {}", + // hostDeviceName, e.getMessage(), e); + // throw new CloudRuntimeException("Failed to update LUN device allocation: " + e.getMessage(), e); + // } + // } + @Override public Pair, Integer> searchForVlans(final ListVlanIpRangesCmd cmd) { // If an account name and domain ID are specified, look up the account @@ -3265,70 +3913,6 @@ public Pair setConsoleAccessForVm(long vmId, String sessionUuid return new Pair<>(result, details); } - @Override - public ListResponse listHostDevices(ListHostDevicesCmd cmd) { - Long id = cmd.getId(); - HostVO hostVO = _hostDao.findById(id); - if (hostVO == null) { - throw new CloudRuntimeException("Host not found with ID: " + id); - } - - ListHostDeviceCommand pciCmd = new ListHostDeviceCommand(id); - Answer answer; - try { - answer = _agentMgr.send(hostVO.getId(), pciCmd); - } catch (Exception e) { - String errorMsg = "Error sending ListHostDevicesCommand: " + e.getMessage(); - logger.error(errorMsg, e); - throw new CloudRuntimeException(errorMsg, e); - } - - if (answer == null) { - throw new CloudRuntimeException("Answer is null"); - } - if (!answer.getResult()) { - String errorDetails = (answer.getDetails() != null) ? answer.getDetails() - : "No additional details available"; - String errorMsg = "Answer result is false. Details: " + errorDetails; - logger.error(errorMsg); - throw new CloudRuntimeException(errorMsg); - } - if (!(answer instanceof ListHostDeviceAnswer)) { - throw new CloudRuntimeException("Answer is not an instance of listHostDeviceAnswer"); - } - - ListHostDeviceAnswer pciAnswer = (ListHostDeviceAnswer) answer; - if (!pciAnswer.isSuccessMessage()) { - throw new IllegalArgumentException("Failed to list VM PCI objects."); - } - - List responses = new ArrayList<>(); - ListResponse listResponse = new ListResponse<>(); - - List hostDevicesTexts = pciAnswer.getHostDevicesTexts(); - - List hostDevicesNames = new ArrayList<>(); - List pciDescriptions = new ArrayList<>(); - - for (String hostDevicesText : hostDevicesTexts) { - String[] parts = hostDevicesText.split(": ", 2); - if (parts.length == 2) { - hostDevicesNames.add(parts[0].trim()); - pciDescriptions.add(parts[1].trim()); - } else { - logger.warn("Unexpected PCI info format: " + hostDevicesText); - } - } - - ListHostDevicesResponse response = new ListHostDevicesResponse(); - response.setHostDevicesNames(hostDevicesNames); - response.setHostDevicesTexts(pciDescriptions); - responses.add(response); - - listResponse.setResponses(responses); - return listResponse; - } - @Override public String getConsoleAccessAddress(long vmId) { final VMInstanceVO vm = _vmInstanceDao.findById(vmId); @@ -4232,7 +4816,11 @@ public List> getCommands() { cmdList.add(AllocateVbmcToVMCmd.class); cmdList.add(RemoveVbmcToVMCmd.class); cmdList.add(ListHostDevicesCmd.class); - + cmdList.add(UpdateHostDevicesCmd.class); + // cmdList.add(ListHostUsbDevicesCmd.class); + // cmdList.add(ListHostLunDevicesCmd.class); + // cmdList.add(UpdateHostUsbDevicesCmd.class); + // cmdList.add(UpdateHostLunDevicesCmd.class); //object store APIs cmdList.add(AddObjectStoragePoolCmd.class); cmdList.add(ListObjectStoragePoolsCmd.class); @@ -5789,7 +6377,7 @@ private LicenseCheckerResponse checkLicense(HostVO host) { // "License error for host " + host.getName(), // "License check failed: " + errorMessage // ); - } else { + } else { boolean isExpired = jsonNode.get("expiry_date").asBoolean(); boolean isIssued = jsonNode.get("issued_date").asBoolean(); String expiryDateStr = jsonNode.get("expired").asText(); @@ -5839,7 +6427,7 @@ private LicenseCheckerResponse checkLicense(HostVO host) { connection.disconnect(); } } - return response; + return response; } catch (Exception e) { logger.error("Error checking license for host: " + host.getId(), e); throw new CloudRuntimeException("라이선스 체크 실패: " + e.getMessage()); diff --git a/ui/public/locales/en.json b/ui/public/locales/en.json index 757e2cb4558b..05f16117436e 100644 --- a/ui/public/locales/en.json +++ b/ui/public/locales/en.json @@ -4769,5 +4769,14 @@ "label.theme.cyan": "Cyan", "label.theme.polar.green": "Polar Green", "label.theme.geek.blue": "Geek Blue", -"label.theme.golden.purple": "Golden Purple" +"label.theme.golden.purple": "Golden Purple", +"label.usb.devices": "USB Devices", +"label.lun.devices": "LUN Devices", +"label.other.devices": "Other Devices", +"message.no.vm.found": "VM not found", +"Message.Success.Remove.alloc": "Deallocation of device completed", +"message.error.remove.alloc": "Unassigning device failed", +"message.delete.device.alloc": "Unassigning devices in virtual machines", +"message.success.allocate.device": "Device allocation completed", +"message.confirm.delete.device": "Are you sure you want to delete the device" } diff --git a/ui/public/locales/ko_KR.json b/ui/public/locales/ko_KR.json index 74a678643f58..c6d4f21ab131 100644 --- a/ui/public/locales/ko_KR.json +++ b/ui/public/locales/ko_KR.json @@ -4769,5 +4769,14 @@ "label.theme.cyan": "\uc2dc\uc548", "label.theme.polar.green": "\ud3f4\ub77c \uadf8\ub9b0", "label.theme.geek.blue": "\uae31 \ube14\ub8e8", -"label.theme.golden.purple": "\uace8\ub4e0 \ud37c\ud50c" +"label.theme.golden.purple": "\uace8\ub4e0 \ud37c\ud50c", +"label.usb.devices": "USB \ub514\ubc14\uc774\uc2a4", +"label.lun.devices": "LUN \ub514\ubc14\uc774\uc2a4", +"label.other.devices": "\uae30\ud0c0 \ub514\ubc14\uc774\uc2a4", +"message.no.vm.found": "VM\uc744 \ucc3e\uc744 \uc218 \uc5c6\uc2b5\ub2c8\ub2e4.", +"message.success.remove.allocation": "\ub514\ubc14\uc774\uc2a4 \ud560\ub2f9 \ud574\uc81c\uac00 \uc644\ub8cc\ub418\uc5c8\uc2b5\ub2c8\ub2e4.", +"message.error.remove.allocation": "\ub514\ubc14\uc774\uc2a4 \ud560\ub2f9 \ud574\uc81c\uc5d0 \uc2e4\ud328\ud558\uc600\uc2b5\ub2c8\ub2e4.", +"message.delete.device.allocation": "\uc5d0 \uc788\ub294 \ub514\ubc14\uc774\uc2a4 \ud560\ub2f9 \ud574\uc81c", +"message.success.allocate.device": "\ub514\ubc14\uc774\uc2a4 \ud560\ub2f9 \uc644\ub8cc", +"message.confirm.delete.device": "\ub514\ubc14\uc774\uc2a4\ub97c \uc0ad\uc81c\ud558\uc2dc\uaca0\uc2b5\ub2c8\uae4c?" } diff --git a/ui/src/views/compute/InstanceTab.vue b/ui/src/views/compute/InstanceTab.vue index 6253a04771fe..65741185d4f8 100644 --- a/ui/src/views/compute/InstanceTab.vue +++ b/ui/src/views/compute/InstanceTab.vue @@ -115,6 +115,19 @@ :virtualmachine="vm" :loading="loading"/> + +
+ + +
+
+ {{ $t('label.no.pci.devices') }} +
+
@@ -262,7 +275,21 @@ export default { editNicLinkStat: '', dataPreFill: {}, securitygroupids: [], - securityGroupNetworkProviderUseThisVM: false + securityGroupNetworkProviderUseThisVM: false, + hasPciDevices: false, + pciDevices: [], + pciColumns: [ + { + title: this.$t('label.name'), + dataIndex: 'hostDevicesName', + key: 'hostDevicesName' + }, + { + title: this.$t('label.details'), + dataIndex: 'hostDevicesText', + key: 'hostDevicesText' + } + ] } }, created () { @@ -296,21 +323,7 @@ export default { setCurrentTab () { this.currentTab = this.$route.query.tab ? this.$route.query.tab : 'details' }, - handleChangeTab (e) { - this.currentTab = e - const query = Object.assign({}, this.$route.query) - query.tab = e - history.pushState( - {}, - null, - '#' + this.$route.path + '?' + Object.keys(query).map(key => { - return ( - encodeURIComponent(key) + '=' + encodeURIComponent(query[key]) - ) - }).join('&') - ) - }, - fetchData () { + async fetchData () { this.annotations = [] if (!this.vm || !this.vm.id) { return @@ -339,6 +352,17 @@ export default { } } }) + + // PCI 디바이스 할당 여부만 확인 + this.hasPciDevices = false + if (this.vm.details) { + for (const [key, value] of Object.entries(this.vm.details)) { + if (key.startsWith('extraconfig-') && value.includes(' { + if (vmId === vmNumericId) { + const deviceIndex = devices.hostdevicesname.findIndex(name => name === deviceName) + if (deviceIndex !== -1) { + this.pciDevices.push({ + key: deviceName, + hostDevicesName: devices.hostdevicesname[deviceIndex], + hostDevicesText: devices.hostdevicestext[deviceIndex] + }) + } + } + }) + } + } catch (error) { + console.error('Error fetching PCI devices:', error) + } } } } diff --git a/ui/src/views/infra/ListHostDevicesTab.vue b/ui/src/views/infra/ListHostDevicesTab.vue index 101f1e1422c6..7426db3d03c1 100644 --- a/ui/src/views/infra/ListHostDevicesTab.vue +++ b/ui/src/views/infra/ListHostDevicesTab.vue @@ -17,33 +17,68 @@ @@ -170,4 +829,11 @@ export default { :deep(.ant-table-tbody) > tr > td { cursor: pointer; } + + .pci-device-item { + display: flex; + justify-content: space-between; + align-items: center; + width: 100%; + } diff --git a/ui/src/views/storage/HostDevicesTransfer.vue b/ui/src/views/storage/HostDevicesTransfer.vue index 2ee3a1302b0d..d7b06ebd3400 100644 --- a/ui/src/views/storage/HostDevicesTransfer.vue +++ b/ui/src/views/storage/HostDevicesTransfer.vue @@ -68,83 +68,226 @@ export default { virtualmachines: [], loading: true, form: reactive({ virtualmachineid: null }), - resourceType: 'UserVm' + resourceType: 'UserVm', + currentVmDevices: new Set(), + currentScsiAddresses: new Set() } }, created () { this.fetchVMs() }, + watch: { + showAddModal: { + immediate: true, + handler (newVal) { + if (newVal) { + this.fetchVMs() + } + } + } + }, methods: { - fetchVMs () { + refreshVMList () { + if (!this.resource || !this.resource.id) { + this.loading = false + return Promise.reject(new Error('Invalid resource')) + } + this.loading = true - const params = { hostid: this.resource.id, details: 'min' } + const params = { hostid: this.resource.id, details: 'min', listall: true } const vmStates = ['Running'] - vmStates.forEach((state) => { - params.state = state - api('listVirtualMachines', params).then(response => { - this.virtualmachines = this.virtualmachines.concat(response.listvirtualmachinesresponse.virtualmachine || []) - }).catch(error => { - this.$notifyError(error.message || 'Failed to fetch VMs') - }).finally(() => { - this.loading = false + return Promise.all(vmStates.map(state => { + return api('listVirtualMachines', { ...params, state }) + .then(vmResponse => vmResponse.listvirtualmachinesresponse.virtualmachine || []) + })).then(vmArrays => { + const vms = vmArrays.flat() + + return Promise.all(vms.map(vm => { + return api('listVirtualMachines', { + id: vm.id, + details: 'all' + }).then(detailResponse => { + const vmDetails = detailResponse.listvirtualmachinesresponse.virtualmachine[0] + + // XML 형식이 아닌 extraconfig 제거 + if (vmDetails.details) { + const filteredDetails = {} + Object.entries(vmDetails.details).forEach(([key, value]) => { + if (!key.startsWith('extraconfig-') || value.includes(' { + return api('listHostDevices', { + id: this.resource.id + }).then(latestResponse => { + const latestDevices = latestResponse.listhostdevicesresponse?.listhostdevices?.[0] + const latestAllocatedVmIds = new Set() + + if (latestDevices?.vmallocations) { + Object.values(latestDevices.vmallocations).forEach(vmId => { + if (vmId) { + latestAllocatedVmIds.add(vmId.toString()) + } + }) + } + + this.virtualmachines = detailedVms.filter(vm => { + if (latestAllocatedVmIds.has(vm.id.toString()) && + vm.details?.['extraconfig-1']?.toLowerCase().includes('usb') || + vm.details?.['extraconfig-1']?.toLowerCase().includes('disk type=\'block\' device=\'lun\'')) { + return false + } + return true + }) }) + }).catch(error => { + this.$notifyError(error.message || 'Failed to fetch VMs') + }).finally(() => { + this.loading = false }) }, + + fetchVMs () { + this.form.virtualmachineid = undefined + return this.refreshVMList() + }, + handleSubmit () { + if (!this.resource || !this.resource.id) { + this.$notifyError(this.$t('message.error.invalid.resource')) + return + } + if (!this.form.virtualmachineid) { this.$notifyError(this.$t('message.error.select.vm')) return } this.loading = true - const vmId = this.form.virtualmachineid const hostDevicesName = this.resource.hostDevicesName api('listVirtualMachines', { - id: vmId, - details: 'min' + id: this.form.virtualmachineid, + details: 'all' }).then(response => { - const vm = response.listvirtualmachinesresponse.virtualmachine[0] - const details = vm.details || {} + const vm = response?.listvirtualmachinesresponse?.virtualmachine?.[0] + const details = vm?.details || {} - const xmlConfig = this.generateXmlConfig(hostDevicesName) + // VM 이벤트 리스너 등록 + this.registerVMEventListener(vm.id, hostDevicesName) - const params = { id: vmId } + let nextConfigNum = 1 + let lastXmlConfig = 0 - // 기존 details 값을 유지하면서 새로운 값 추가 - Object.keys(details).forEach(key => { - params[`details[0].${key}`] = details[key] + // XML 설정이 있는 마지막 extraconfig 번호 찾기 + Object.entries(details).forEach(([key, value]) => { + if (key.startsWith('extraconfig-') && value.includes(' { + if (key.startsWith('extraconfig-') && value.includes(' { + return api('updateHostDevices', { + hostid: this.resource.id, + hostdevicesname: hostDevicesName, + virtualmachineid: this.form.virtualmachineid + }) + }) }).then(() => { - this.$message.success(this.$t('message.success.update.vm')) - this.closeAction() + this.$message.success(this.$t('message.success.allocate.device')) + this.$emit('device-allocated') + this.$emit('allocation-completed') + this.$emit('close-action') }).catch(error => { - this.$notifyError(error.message || 'Failed to update VM') + this.$notifyError(error) this.formRef.value.scrollToField('virtualmachineid') }).finally(() => { this.loading = false }) }, - generateXmlConfig (hostDevicesName) { - const [pciAddress] = hostDevicesName.split(' ') + registerVMEventListener (vmId, hostDevicesName) { + const eventTypes = ['DestroyVM', 'ExpungeVM', 'UpdateVirtualMachine'] + + eventTypes.forEach(eventType => { + this.$store.dispatch('event/subscribe', { + eventType: eventType, + resourceId: vmId, + callback: async () => { + try { + if (eventType === 'UpdateVirtualMachine') { + // VM의 현재 상태 확인 + const response = await api('listVirtualMachines', { + id: vmId, + details: 'all' + }) + + const vm = response?.listvirtualmachinesresponse?.virtualmachine?.[0] + const details = vm?.details || {} + + // extraconfig에 해당 호스트 디바이스 설정이 남아있는지 확인 + const hasDeviceConfig = Object.values(details).some(value => + value.includes(' - + -
+
- `.trim() },