mirror of https://github.com/apache/cloudstack.git
Apple FR66 - Host Control Plane Status (#213)
* Apple FR66 - Host Control Plane Status * Apple FR66 - use Offline instead of Disconnected * Apple FR66: fix smoke test test_router_host_control_state * Apple FR66: reorder import * Apple FR66: revert DetailsTab.vue and apply new changes * Update PR: update en.json * Update PR: add hostcontrolstate to routers/systemvms * Update PR: test stop/start cloudstack-agent in smoke test * Update PR: fix UI build error (The template root requires exactly one element vue/valid-template-root) * Update PR: update message on ui * Update PR: Disable rebootVM and create vm/volume snapshot for KVM VMs * Update PR: add more unit tests
This commit is contained in:
parent
f77ab62377
commit
11f38ad102
|
|
@ -0,0 +1,41 @@
|
|||
// 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.host;
|
||||
|
||||
import com.cloud.resource.ResourceState;
|
||||
|
||||
public enum ControlState {
|
||||
Enabled,
|
||||
Disabled,
|
||||
Offline,
|
||||
Maintenance,
|
||||
Unknown;
|
||||
|
||||
public static ControlState getControlState(Status hostStatus, ResourceState hostResourceState) {
|
||||
if (hostStatus == null || Status.Unknown.equals(hostStatus) || hostResourceState == null) {
|
||||
return ControlState.Unknown;
|
||||
} else if (hostStatus.lostConnection()) {
|
||||
return Offline;
|
||||
} else if (ResourceState.isMaintenanceState(hostResourceState)) {
|
||||
return Maintenance;
|
||||
} else if (ResourceState.Enabled.equals(hostResourceState)) {
|
||||
return Enabled;
|
||||
} else {
|
||||
return Disabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -192,6 +192,7 @@ public class ApiConstants {
|
|||
public static final String HOST_ID = "hostid";
|
||||
public static final String HOST_IDS = "hostids";
|
||||
public static final String HOST_NAME = "hostname";
|
||||
public static final String HOST_CONTROL_STATE = "hostcontrolstate";
|
||||
public static final String HOSTS_MAP = "hostsmap";
|
||||
public static final String HYPERVISOR = "hypervisor";
|
||||
public static final String INLINE = "inline";
|
||||
|
|
|
|||
|
|
@ -89,6 +89,10 @@ public class DomainRouterResponse extends BaseResponseWithAnnotations implements
|
|||
@Param(description = "the hostname for the router")
|
||||
private String hostName;
|
||||
|
||||
@SerializedName(ApiConstants.HOST_CONTROL_STATE)
|
||||
@Param(description = "the control state of the host for the router")
|
||||
private String hostControlState;
|
||||
|
||||
@SerializedName("hypervisor")
|
||||
@Param(description = "the hypervisor on which the template runs")
|
||||
private String hypervisor;
|
||||
|
|
@ -298,6 +302,10 @@ public class DomainRouterResponse extends BaseResponseWithAnnotations implements
|
|||
this.hostName = hostName;
|
||||
}
|
||||
|
||||
public void setHostControlState(String hostControlState) {
|
||||
this.hostControlState = hostControlState;
|
||||
}
|
||||
|
||||
public String getHypervisor() {
|
||||
return hypervisor;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -90,6 +90,10 @@ public class SystemVmResponse extends BaseResponseWithAnnotations {
|
|||
@Param(description = "the hostname for the system VM")
|
||||
private String hostName;
|
||||
|
||||
@SerializedName(ApiConstants.HOST_CONTROL_STATE)
|
||||
@Param(description = "the control state of the host for the system VM")
|
||||
private String hostControlState;
|
||||
|
||||
@SerializedName("hypervisor")
|
||||
@Param(description = "the hypervisor on which the template runs")
|
||||
private String hypervisor;
|
||||
|
|
@ -283,6 +287,14 @@ public class SystemVmResponse extends BaseResponseWithAnnotations {
|
|||
this.hostName = hostName;
|
||||
}
|
||||
|
||||
public String getHostControlState() {
|
||||
return hostControlState;
|
||||
}
|
||||
|
||||
public void setHostControlState(String hostControlState) {
|
||||
this.hostControlState = hostControlState;
|
||||
}
|
||||
|
||||
public String getHypervisor() {
|
||||
return hypervisor;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -118,6 +118,10 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
|
|||
@Param(description = "the name of the host for the virtual machine")
|
||||
private String hostName;
|
||||
|
||||
@SerializedName(ApiConstants.HOST_CONTROL_STATE)
|
||||
@Param(description = "the control state of the host for the virtual machine")
|
||||
private String hostControlState;
|
||||
|
||||
@SerializedName(ApiConstants.TEMPLATE_ID)
|
||||
@Param(description = "the ID of the template for the virtual machine. A -1 is returned if the virtual machine was created from an ISO file.")
|
||||
private String templateId;
|
||||
|
|
@ -449,6 +453,10 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
|
|||
return hostName;
|
||||
}
|
||||
|
||||
public String getHostControlState() {
|
||||
return hostControlState;
|
||||
}
|
||||
|
||||
public String getTemplateId() {
|
||||
return templateId;
|
||||
}
|
||||
|
|
@ -687,6 +695,10 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co
|
|||
this.hostName = hostName;
|
||||
}
|
||||
|
||||
public void setHostControlState(String hostControlState) {
|
||||
this.hostControlState = hostControlState;
|
||||
}
|
||||
|
||||
public void setTemplateId(String templateId) {
|
||||
this.templateId = templateId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,98 @@
|
|||
// 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.host;
|
||||
|
||||
import com.cloud.resource.ResourceState;
|
||||
|
||||
import junit.framework.TestCase;
|
||||
|
||||
import org.junit.Assert;
|
||||
import org.junit.Test;
|
||||
|
||||
public class ControlStateTest extends TestCase {
|
||||
|
||||
void verifyHostControlState(Status hostStatus, ResourceState hostResourceState, ControlState expectedControlState) {
|
||||
Assert.assertEquals(expectedControlState, ControlState.getControlState(hostStatus, hostResourceState));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testHostControlState() {
|
||||
// Unknown state
|
||||
verifyHostControlState(null, null, ControlState.Unknown);
|
||||
verifyHostControlState(null, ResourceState.Enabled, ControlState.Unknown);
|
||||
verifyHostControlState(Status.Up, null, ControlState.Unknown);
|
||||
verifyHostControlState(Status.Disconnected, null, ControlState.Unknown);
|
||||
verifyHostControlState(Status.Down, null, ControlState.Unknown);
|
||||
|
||||
verifyHostControlState(Status.Unknown, null, ControlState.Unknown);
|
||||
verifyHostControlState(Status.Unknown, ResourceState.Enabled, ControlState.Unknown);
|
||||
verifyHostControlState(Status.Unknown, ResourceState.ErrorInPrepareForMaintenance, ControlState.Unknown);
|
||||
verifyHostControlState(Status.Unknown, ResourceState.PrepareForMaintenance, ControlState.Unknown);
|
||||
verifyHostControlState(Status.Unknown, ResourceState.ErrorInMaintenance, ControlState.Unknown);
|
||||
verifyHostControlState(Status.Unknown, ResourceState.Maintenance, ControlState.Unknown);
|
||||
verifyHostControlState(Status.Unknown, ResourceState.Creating, ControlState.Unknown);
|
||||
verifyHostControlState(Status.Unknown, ResourceState.Disabled, ControlState.Unknown);
|
||||
verifyHostControlState(Status.Unknown, ResourceState.Error, ControlState.Unknown);
|
||||
verifyHostControlState(Status.Unknown, ResourceState.Degraded, ControlState.Unknown);
|
||||
|
||||
// Host is Up and Enabled
|
||||
verifyHostControlState(Status.Creating, ResourceState.Enabled, ControlState.Enabled);
|
||||
verifyHostControlState(Status.Connecting, ResourceState.Enabled, ControlState.Enabled);
|
||||
verifyHostControlState(Status.Up, ResourceState.Enabled, ControlState.Enabled);
|
||||
|
||||
// Host is Up and not Enabled
|
||||
verifyHostControlState(Status.Up, ResourceState.Creating, ControlState.Disabled);
|
||||
verifyHostControlState(Status.Up, ResourceState.Disabled, ControlState.Disabled);
|
||||
verifyHostControlState(Status.Up, ResourceState.Error, ControlState.Disabled);
|
||||
verifyHostControlState(Status.Up, ResourceState.Degraded, ControlState.Disabled);
|
||||
|
||||
// Host is Up and Maintenance mode
|
||||
verifyHostControlState(Status.Up, ResourceState.ErrorInPrepareForMaintenance, ControlState.Maintenance);
|
||||
verifyHostControlState(Status.Up, ResourceState.PrepareForMaintenance, ControlState.Maintenance);
|
||||
verifyHostControlState(Status.Up, ResourceState.ErrorInMaintenance, ControlState.Maintenance);
|
||||
verifyHostControlState(Status.Up, ResourceState.Maintenance, ControlState.Maintenance);
|
||||
|
||||
// Host is Creating and not Enabled
|
||||
verifyHostControlState(Status.Creating, ResourceState.Creating, ControlState.Disabled);
|
||||
verifyHostControlState(Status.Creating, ResourceState.Disabled, ControlState.Disabled);
|
||||
verifyHostControlState(Status.Creating, ResourceState.Error, ControlState.Disabled);
|
||||
verifyHostControlState(Status.Creating, ResourceState.Degraded, ControlState.Disabled);
|
||||
|
||||
// Host is Connecting and not Enabled
|
||||
verifyHostControlState(Status.Connecting, ResourceState.Creating, ControlState.Disabled);
|
||||
verifyHostControlState(Status.Connecting, ResourceState.Disabled, ControlState.Disabled);
|
||||
verifyHostControlState(Status.Connecting, ResourceState.Error, ControlState.Disabled);
|
||||
verifyHostControlState(Status.Connecting, ResourceState.Degraded, ControlState.Disabled);
|
||||
|
||||
// Host in other states and Enabled
|
||||
verifyHostControlState(Status.Down, ResourceState.Enabled, ControlState.Offline);
|
||||
verifyHostControlState(Status.Disconnected, ResourceState.Enabled, ControlState.Offline);
|
||||
verifyHostControlState(Status.Alert, ResourceState.Enabled, ControlState.Offline);
|
||||
verifyHostControlState(Status.Removed, ResourceState.Enabled, ControlState.Offline);
|
||||
verifyHostControlState(Status.Error, ResourceState.Enabled, ControlState.Offline);
|
||||
verifyHostControlState(Status.Rebalancing, ResourceState.Enabled, ControlState.Offline);
|
||||
|
||||
// Host in other states and Disabled
|
||||
verifyHostControlState(Status.Down, ResourceState.Disabled, ControlState.Offline);
|
||||
verifyHostControlState(Status.Disconnected, ResourceState.Disabled, ControlState.Offline);
|
||||
verifyHostControlState(Status.Alert, ResourceState.Disabled, ControlState.Offline);
|
||||
verifyHostControlState(Status.Removed, ResourceState.Disabled, ControlState.Offline);
|
||||
verifyHostControlState(Status.Error, ResourceState.Disabled, ControlState.Offline);
|
||||
verifyHostControlState(Status.Rebalancing, ResourceState.Disabled, ControlState.Offline);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -586,6 +586,8 @@ SELECT
|
|||
`host`.`uuid` AS `host_uuid`,
|
||||
`host`.`name` AS `host_name`,
|
||||
`host`.`cluster_id` AS `cluster_id`,
|
||||
`host`.`status` AS `host_status`,
|
||||
`host`.`resource_state` AS `host_resource_state`,
|
||||
`vm_template`.`id` AS `template_id`,
|
||||
`vm_template`.`uuid` AS `template_uuid`,
|
||||
`vm_template`.`name` AS `template_name`,
|
||||
|
|
@ -725,3 +727,110 @@ FROM
|
|||
AND (`custom_speed`.`name` = 'CpuSpeed'))))
|
||||
LEFT JOIN `user_vm_details` `custom_ram_size` ON (((`custom_ram_size`.`vm_id` = `vm_instance`.`id`)
|
||||
AND (`custom_ram_size`.`name` = 'memory'))));
|
||||
|
||||
DROP VIEW IF EXISTS `cloud`.`domain_router_view`;
|
||||
CREATE VIEW `cloud`.`domain_router_view` AS
|
||||
select
|
||||
vm_instance.id id,
|
||||
vm_instance.name name,
|
||||
account.id account_id,
|
||||
account.uuid account_uuid,
|
||||
account.account_name account_name,
|
||||
account.type account_type,
|
||||
domain.id domain_id,
|
||||
domain.uuid domain_uuid,
|
||||
domain.name domain_name,
|
||||
domain.path domain_path,
|
||||
projects.id project_id,
|
||||
projects.uuid project_uuid,
|
||||
projects.name project_name,
|
||||
vm_instance.uuid uuid,
|
||||
vm_instance.created created,
|
||||
vm_instance.state state,
|
||||
vm_instance.removed removed,
|
||||
vm_instance.pod_id pod_id,
|
||||
vm_instance.instance_name instance_name,
|
||||
host_pod_ref.uuid pod_uuid,
|
||||
data_center.id data_center_id,
|
||||
data_center.uuid data_center_uuid,
|
||||
data_center.name data_center_name,
|
||||
data_center.networktype data_center_type,
|
||||
data_center.dns1 dns1,
|
||||
data_center.dns2 dns2,
|
||||
data_center.ip6_dns1 ip6_dns1,
|
||||
data_center.ip6_dns2 ip6_dns2,
|
||||
host.id host_id,
|
||||
host.uuid host_uuid,
|
||||
host.name host_name,
|
||||
host.hypervisor_type,
|
||||
host.cluster_id cluster_id,
|
||||
host.status host_status,
|
||||
host.resource_state host_resource_state,
|
||||
vm_template.id template_id,
|
||||
vm_template.uuid template_uuid,
|
||||
service_offering.id service_offering_id,
|
||||
disk_offering.uuid service_offering_uuid,
|
||||
disk_offering.name service_offering_name,
|
||||
nics.id nic_id,
|
||||
nics.uuid nic_uuid,
|
||||
nics.network_id network_id,
|
||||
nics.ip4_address ip_address,
|
||||
nics.ip6_address ip6_address,
|
||||
nics.ip6_gateway ip6_gateway,
|
||||
nics.ip6_cidr ip6_cidr,
|
||||
nics.default_nic is_default_nic,
|
||||
nics.gateway gateway,
|
||||
nics.netmask netmask,
|
||||
nics.mac_address mac_address,
|
||||
nics.broadcast_uri broadcast_uri,
|
||||
nics.isolation_uri isolation_uri,
|
||||
vpc.id vpc_id,
|
||||
vpc.uuid vpc_uuid,
|
||||
vpc.name vpc_name,
|
||||
networks.uuid network_uuid,
|
||||
networks.name network_name,
|
||||
networks.network_domain network_domain,
|
||||
networks.traffic_type traffic_type,
|
||||
networks.guest_type guest_type,
|
||||
async_job.id job_id,
|
||||
async_job.uuid job_uuid,
|
||||
async_job.job_status job_status,
|
||||
async_job.account_id job_account_id,
|
||||
domain_router.template_version template_version,
|
||||
domain_router.scripts_version scripts_version,
|
||||
domain_router.is_redundant_router is_redundant_router,
|
||||
domain_router.redundant_state redundant_state,
|
||||
domain_router.stop_pending stop_pending,
|
||||
domain_router.role role
|
||||
from
|
||||
`cloud`.`domain_router`
|
||||
inner join
|
||||
`cloud`.`vm_instance` ON vm_instance.id = domain_router.id
|
||||
inner join
|
||||
`cloud`.`account` ON vm_instance.account_id = account.id
|
||||
inner join
|
||||
`cloud`.`domain` ON vm_instance.domain_id = domain.id
|
||||
left join
|
||||
`cloud`.`host_pod_ref` ON vm_instance.pod_id = host_pod_ref.id
|
||||
left join
|
||||
`cloud`.`projects` ON projects.project_account_id = account.id
|
||||
left join
|
||||
`cloud`.`data_center` ON vm_instance.data_center_id = data_center.id
|
||||
left join
|
||||
`cloud`.`host` ON vm_instance.host_id = host.id
|
||||
left join
|
||||
`cloud`.`vm_template` ON vm_instance.vm_template_id = vm_template.id
|
||||
left join
|
||||
`cloud`.`service_offering` ON vm_instance.service_offering_id = service_offering.id
|
||||
left join
|
||||
`cloud`.`disk_offering` ON vm_instance.service_offering_id = disk_offering.id
|
||||
left join
|
||||
`cloud`.`nics` ON vm_instance.id = nics.instance_id and nics.removed is null
|
||||
left join
|
||||
`cloud`.`networks` ON nics.network_id = networks.id
|
||||
left join
|
||||
`cloud`.`vpc` ON domain_router.vpc_id = vpc.id and vpc.removed is null
|
||||
left join
|
||||
`cloud`.`async_job` ON async_job.instance_id = vm_instance.id
|
||||
and async_job.instance_type = 'DomainRouter'
|
||||
and async_job.job_status = 0;
|
||||
|
|
|
|||
|
|
@ -36,6 +36,7 @@ import java.util.stream.Collectors;
|
|||
|
||||
import javax.inject.Inject;
|
||||
|
||||
import com.cloud.host.ControlState;
|
||||
import com.cloud.utils.security.CertificateHelper;
|
||||
import com.cloud.user.UserData;
|
||||
import org.apache.cloudstack.acl.ControlledEntity;
|
||||
|
|
@ -1499,6 +1500,7 @@ public class ApiResponseHelper implements ResponseGenerator {
|
|||
if (host != null) {
|
||||
vmResponse.setHostId(host.getUuid());
|
||||
vmResponse.setHostName(host.getName());
|
||||
vmResponse.setHostControlState(ControlState.getControlState(host.getStatus(), host.getResourceState()).toString());
|
||||
vmResponse.setHypervisor(host.getHypervisorType().toString());
|
||||
}
|
||||
} else if (vm.getLastHostId() != null) {
|
||||
|
|
|
|||
|
|
@ -37,6 +37,7 @@ import com.cloud.api.ApiDBUtils;
|
|||
import com.cloud.api.ApiResponseHelper;
|
||||
import com.cloud.api.query.vo.DomainRouterJoinVO;
|
||||
import com.cloud.dc.HostPodVO;
|
||||
import com.cloud.host.ControlState;
|
||||
import com.cloud.network.Networks.TrafficType;
|
||||
import com.cloud.network.router.VirtualRouter;
|
||||
import com.cloud.network.router.VirtualRouter.Role;
|
||||
|
|
@ -110,6 +111,7 @@ public class DomainRouterJoinDaoImpl extends GenericDaoBase<DomainRouterJoinVO,
|
|||
if (router.getHostId() != null) {
|
||||
routerResponse.setHostId(router.getHostUuid());
|
||||
routerResponse.setHostName(router.getHostName());
|
||||
routerResponse.setHostControlState(ControlState.getControlState(router.getHostStatus(), router.getHostResourceState()).toString());
|
||||
routerResponse.setHypervisor(router.getHypervisorType().toString());
|
||||
}
|
||||
routerResponse.setPodId(router.getPodUuid());
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ import com.cloud.api.ApiDBUtils;
|
|||
import com.cloud.api.ApiResponseHelper;
|
||||
import com.cloud.api.query.vo.UserVmJoinVO;
|
||||
import com.cloud.gpu.GPU;
|
||||
import com.cloud.host.ControlState;
|
||||
import com.cloud.service.ServiceOfferingDetailsVO;
|
||||
import com.cloud.storage.GuestOS;
|
||||
import com.cloud.user.Account;
|
||||
|
|
@ -166,6 +167,9 @@ public class UserVmJoinDaoImpl extends GenericDaoBaseWithTagInformation<UserVmJo
|
|||
userVmResponse.setHostId(userVm.getHostUuid());
|
||||
userVmResponse.setHostName(userVm.getHostName());
|
||||
}
|
||||
if (userVm.getHostStatus() != null) {
|
||||
userVmResponse.setHostControlState(ControlState.getControlState(userVm.getHostStatus(), userVm.getHostResourceState()).toString());
|
||||
}
|
||||
|
||||
if (details.contains(VMDetails.all) || details.contains(VMDetails.tmpl)) {
|
||||
userVmResponse.setTemplateId(userVm.getTemplateUuid());
|
||||
|
|
|
|||
|
|
@ -26,11 +26,13 @@ import javax.persistence.Enumerated;
|
|||
import javax.persistence.Id;
|
||||
import javax.persistence.Table;
|
||||
|
||||
import com.cloud.host.Status;
|
||||
import com.cloud.hypervisor.Hypervisor;
|
||||
import com.cloud.network.Network.GuestType;
|
||||
import com.cloud.network.Networks.TrafficType;
|
||||
import com.cloud.network.router.VirtualRouter;
|
||||
import com.cloud.network.router.VirtualRouter.RedundantState;
|
||||
import com.cloud.resource.ResourceState;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
import com.cloud.vm.VirtualMachine;
|
||||
import com.cloud.vm.VirtualMachine.State;
|
||||
|
|
@ -127,6 +129,12 @@ public class DomainRouterJoinVO extends BaseViewVO implements ControlledViewEnti
|
|||
@Column(name = "host_name", nullable = false)
|
||||
private String hostName;
|
||||
|
||||
@Column(name = "host_status")
|
||||
private Status hostStatus;
|
||||
|
||||
@Column(name = "host_resource_state")
|
||||
private ResourceState hostResourceState;
|
||||
|
||||
@Column(name="hypervisor_type")
|
||||
@Enumerated(value=EnumType.STRING)
|
||||
private Hypervisor.HypervisorType hypervisorType;
|
||||
|
|
@ -346,6 +354,14 @@ public class DomainRouterJoinVO extends BaseViewVO implements ControlledViewEnti
|
|||
return hostName;
|
||||
}
|
||||
|
||||
public Status getHostStatus() {
|
||||
return hostStatus;
|
||||
}
|
||||
|
||||
public ResourceState getHostResourceState() {
|
||||
return hostResourceState;
|
||||
}
|
||||
|
||||
public Hypervisor.HypervisorType getHypervisorType() {
|
||||
return hypervisorType;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,9 +29,11 @@ import javax.persistence.Id;
|
|||
import javax.persistence.Table;
|
||||
import javax.persistence.Transient;
|
||||
|
||||
import com.cloud.host.Status;
|
||||
import com.cloud.hypervisor.Hypervisor.HypervisorType;
|
||||
import com.cloud.network.Network.GuestType;
|
||||
import com.cloud.network.Networks.TrafficType;
|
||||
import com.cloud.resource.ResourceState;
|
||||
import com.cloud.storage.Storage.StoragePoolType;
|
||||
import com.cloud.storage.Volume;
|
||||
import com.cloud.utils.db.GenericDao;
|
||||
|
|
@ -169,9 +171,15 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
|
|||
@Column(name = "host_uuid")
|
||||
private String hostUuid;
|
||||
|
||||
@Column(name = "host_name", nullable = false)
|
||||
@Column(name = "host_name")
|
||||
private String hostName;
|
||||
|
||||
@Column(name = "host_status")
|
||||
private Status hostStatus;
|
||||
|
||||
@Column(name = "host_resource_state")
|
||||
private ResourceState hostResourceState;
|
||||
|
||||
@Column(name = "template_id", updatable = true, nullable = true, length = 17)
|
||||
private long templateId;
|
||||
|
||||
|
|
@ -596,6 +604,14 @@ public class UserVmJoinVO extends BaseViewWithTagInformationVO implements Contro
|
|||
return hostName;
|
||||
}
|
||||
|
||||
public Status getHostStatus() {
|
||||
return hostStatus;
|
||||
}
|
||||
|
||||
public ResourceState getHostResourceState() {
|
||||
return hostResourceState;
|
||||
}
|
||||
|
||||
public long getTemplateId() {
|
||||
return templateId;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,254 @@
|
|||
#!/usr/bin/env python
|
||||
# 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.
|
||||
|
||||
"""
|
||||
Tests for host control state
|
||||
"""
|
||||
|
||||
from marvin.cloudstackAPI import updateHost
|
||||
from nose.plugins.attrib import attr
|
||||
from marvin.cloudstackTestCase import cloudstackTestCase
|
||||
from marvin.lib.common import (get_domain,
|
||||
get_zone,
|
||||
get_template,
|
||||
list_hosts,
|
||||
list_routers,
|
||||
list_ssvms)
|
||||
from marvin.lib.base import (Account,
|
||||
Domain,
|
||||
Host,
|
||||
ServiceOffering,
|
||||
VirtualMachine)
|
||||
from marvin.sshClient import SshClient
|
||||
import time
|
||||
|
||||
|
||||
class TestHostControlState(cloudstackTestCase):
|
||||
|
||||
@classmethod
|
||||
def setUpClass(cls):
|
||||
cls.testClient = super(TestHostControlState, cls).getClsTestClient()
|
||||
cls.apiclient = cls.testClient.getApiClient()
|
||||
cls.services = cls.testClient.getParsedTestDataConfig()
|
||||
# Get Zone, Domain and templates
|
||||
cls.zone = get_zone(cls.apiclient, cls.testClient.getZoneForTests())
|
||||
cls.hypervisor = cls.testClient.getHypervisorInfo()
|
||||
cls.hostConfig = cls.config.__dict__["zones"][0].__dict__["pods"][0].__dict__["clusters"][0].__dict__["hosts"][0].__dict__
|
||||
|
||||
cls.template = get_template(
|
||||
cls.apiclient,
|
||||
cls.zone.id,
|
||||
cls.hypervisor
|
||||
)
|
||||
|
||||
cls.services["virtual_machine"]["zoneid"] = cls.zone.id
|
||||
cls.services["template"] = cls.template.id
|
||||
cls.services["zoneid"] = cls.zone.id
|
||||
|
||||
cls.domain = Domain.create(
|
||||
cls.apiclient,
|
||||
cls.services["acl"]["domain1"]
|
||||
)
|
||||
cls.account = Account.create(
|
||||
cls.apiclient,
|
||||
cls.services["account"],
|
||||
domainid=cls.domain.id
|
||||
)
|
||||
cls.service_offering = ServiceOffering.create(
|
||||
cls.apiclient,
|
||||
cls.services["service_offerings"]["tiny"]
|
||||
)
|
||||
cls.vm = VirtualMachine.create(
|
||||
cls.apiclient,
|
||||
cls.services["virtual_machine"],
|
||||
templateid=cls.template.id,
|
||||
accountid=cls.account.name,
|
||||
domainid=cls.account.domainid,
|
||||
serviceofferingid=cls.service_offering.id
|
||||
)
|
||||
|
||||
cls._cleanup = [
|
||||
cls.domain,
|
||||
cls.account,
|
||||
cls.vm,
|
||||
cls.service_offering
|
||||
]
|
||||
return
|
||||
|
||||
@classmethod
|
||||
def tearDownClass(cls):
|
||||
super(TestHostControlState, cls).tearDownClass()
|
||||
|
||||
def setUp(self):
|
||||
self.apiclient = self.testClient.getApiClient()
|
||||
self.cleanup = []
|
||||
return
|
||||
|
||||
def tearDown(self):
|
||||
super(TestHostControlState, self).tearDown()
|
||||
|
||||
def disable_host(self, id):
|
||||
cmd = updateHost.updateHostCmd()
|
||||
cmd.id = id
|
||||
cmd.allocationstate = "Disable"
|
||||
response = self.apiclient.updateHost(cmd)
|
||||
self.assertEqual(response.resourcestate, "Disabled")
|
||||
|
||||
def enable_host(self, id):
|
||||
cmd = updateHost.updateHostCmd()
|
||||
cmd.id = id
|
||||
cmd.allocationstate = "Enable"
|
||||
response = self.apiclient.updateHost(cmd)
|
||||
self.assertEqual(response.resourcestate, "Enabled")
|
||||
|
||||
def get_host_ipaddress(self, hostId):
|
||||
hosts = list_hosts(
|
||||
self.apiclient,
|
||||
type='Routing',
|
||||
id=hostId
|
||||
)
|
||||
return hosts[0].ipaddress
|
||||
|
||||
def stop_agent(self, host_ipaddress):
|
||||
SshClient(host_ipaddress, port=22, user=self.hostConfig["username"], passwd=self.hostConfig["password"]).execute\
|
||||
("systemctl stop cloudstack-agent || service cloudstack-agent stop")
|
||||
|
||||
def start_agent(self, host_ipaddress):
|
||||
SshClient(host_ipaddress, port=22, user=self.hostConfig["username"], passwd=self.hostConfig["password"]).execute\
|
||||
("systemctl start cloudstack-agent || service cloudstack-agent start")
|
||||
|
||||
def verify_uservm_host_control_state(self, vm_id, state):
|
||||
list_vms = VirtualMachine.list(
|
||||
self.apiclient,
|
||||
id=vm_id
|
||||
)
|
||||
vm = list_vms[0]
|
||||
self.assertEqual(vm.hostcontrolstate,
|
||||
state,
|
||||
msg="host control state should be %s, but it is %s" % (state, vm.hostcontrolstate))
|
||||
|
||||
def verify_ssvm_host_control_state(self, vm_id, state):
|
||||
list_ssvm_response = list_ssvms(
|
||||
self.apiclient,
|
||||
id=vm_id
|
||||
)
|
||||
vm = list_ssvm_response[0]
|
||||
self.assertEqual(vm.hostcontrolstate,
|
||||
state,
|
||||
msg="host control state should be %s, but it is %s" % (state, vm.hostcontrolstate))
|
||||
|
||||
def verify_router_host_control_state(self, vm_id, state):
|
||||
list_router_response = list_routers(
|
||||
self.apiclient,
|
||||
id=vm_id
|
||||
)
|
||||
vm = list_router_response[0]
|
||||
self.assertEqual(vm.hostcontrolstate,
|
||||
state,
|
||||
msg="host control state should be %s, but it is %s" % (state, vm.hostcontrolstate))
|
||||
|
||||
@attr(tags=["basic", "advanced"], required_hardware="false")
|
||||
def test_uservm_host_control_state(self):
|
||||
""" Verify host control state for user vm """
|
||||
# 1. verify hostcontrolstate = Enabled
|
||||
# 2. Disable the host, verify hostcontrolstate = Disabled
|
||||
|
||||
list_vms = VirtualMachine.list(
|
||||
self.apiclient,
|
||||
id=self.vm.id
|
||||
)
|
||||
host_id = list_vms[0].hostid
|
||||
|
||||
self.verify_uservm_host_control_state(self.vm.id, "Enabled")
|
||||
|
||||
self.disable_host(host_id)
|
||||
self.verify_uservm_host_control_state(self.vm.id, "Disabled")
|
||||
|
||||
if self.hypervisor == "kvm":
|
||||
host_ipaddress = self.get_host_ipaddress(host_id)
|
||||
|
||||
self.stop_agent(host_ipaddress)
|
||||
time.sleep(5) # wait for the host to be Disconnected
|
||||
self.verify_uservm_host_control_state(self.vm.id, "Offline")
|
||||
|
||||
self.enable_host(host_id)
|
||||
self.verify_uservm_host_control_state(self.vm.id, "Offline")
|
||||
|
||||
self.start_agent(host_ipaddress)
|
||||
time.sleep(10) # wait for the host to be Up
|
||||
self.verify_uservm_host_control_state(self.vm.id, "Enabled")
|
||||
|
||||
else:
|
||||
self.enable_host(host_id)
|
||||
self.verify_uservm_host_control_state(self.vm.id, "Enabled")
|
||||
|
||||
@attr(tags=["basic", "advanced"], required_hardware="false")
|
||||
def test_ssvm_host_control_state(self):
|
||||
""" Verify host control state for systemvm """
|
||||
# 1. verify hostcontrolstate = Enabled
|
||||
# 2. Disable the host, verify hostcontrolstate = Disabled
|
||||
|
||||
list_ssvm_response = list_ssvms(
|
||||
self.apiclient,
|
||||
systemvmtype='secondarystoragevm',
|
||||
state='Running',
|
||||
zoneid=self.zone.id
|
||||
)
|
||||
self.assertEqual(
|
||||
isinstance(list_ssvm_response, list),
|
||||
True,
|
||||
"Check list response returns a valid list"
|
||||
)
|
||||
ssvm = list_ssvm_response[0]
|
||||
host_id = ssvm.hostid
|
||||
|
||||
self.verify_ssvm_host_control_state(ssvm.id, "Enabled")
|
||||
|
||||
self.disable_host(host_id)
|
||||
self.verify_ssvm_host_control_state(ssvm.id, "Disabled")
|
||||
|
||||
self.enable_host(host_id)
|
||||
self.verify_ssvm_host_control_state(ssvm.id, "Enabled")
|
||||
|
||||
@attr(tags=["basic", "advanced"], required_hardware="false")
|
||||
def test_router_host_control_state(self):
|
||||
""" Verify host control state for router """
|
||||
# 1. verify hostcontrolstate = Enabled
|
||||
# 2. Disable the host, verify hostcontrolstate = Disabled
|
||||
|
||||
list_router_response = list_routers(
|
||||
self.apiclient,
|
||||
state='Running',
|
||||
listall=True,
|
||||
zoneid=self.zone.id
|
||||
)
|
||||
self.assertEqual(
|
||||
isinstance(list_router_response, list),
|
||||
True,
|
||||
"Check list response returns a valid list"
|
||||
)
|
||||
router = list_router_response[0]
|
||||
host_id = router.hostid
|
||||
|
||||
self.verify_router_host_control_state(router.id, "Enabled")
|
||||
|
||||
self.disable_host(host_id)
|
||||
self.verify_router_host_control_state(router.id, "Disabled")
|
||||
|
||||
self.enable_host(host_id)
|
||||
self.verify_router_host_control_state(router.id, "Enabled")
|
||||
|
|
@ -1068,6 +1068,7 @@
|
|||
"label.host.name": "Host Name",
|
||||
"label.host.tag": "Host Tag",
|
||||
"label.host.ueficapability": "UEFI Supported",
|
||||
"label.hostcontrolstate": "Control Plane Status",
|
||||
"label.hostid": "Host",
|
||||
"label.hostname": "Host",
|
||||
"label.hostnamelabel": "Host Name",
|
||||
|
|
@ -3041,6 +3042,8 @@
|
|||
"message.guestnetwork.state.implementing": "Indicates the network configuration is being implemented",
|
||||
"message.guestnetwork.state.setup": "Indicates the network configuration is setup",
|
||||
"message.guestnetwork.state.shutdown": "Indicates the network configuration is being destroyed",
|
||||
"message.host.controlstate": "The Control Plane Status of this instance is ",
|
||||
"message.host.controlstate.retry": "Some actions on this instance will fail, if so please wait a while and retry.",
|
||||
"message.host.dedicated": "Host Dedicated",
|
||||
"message.host.dedication.released": "Host dedication released",
|
||||
"message.info.cloudian.console": "Cloudian Management Console should open in another window",
|
||||
|
|
|
|||
|
|
@ -16,52 +16,61 @@
|
|||
// under the License.
|
||||
|
||||
<template>
|
||||
<a-list
|
||||
size="small"
|
||||
:dataSource="fetchDetails()">
|
||||
<a-list-item slot="renderItem" slot-scope="item" v-if="item in resource">
|
||||
<div>
|
||||
<strong>{{ item === 'service' ? $t('label.supportedservices') : $t('label.' + String(item).toLowerCase()) }}</strong>
|
||||
<br/>
|
||||
<div v-if="Array.isArray(resource[item]) && item === 'service'">
|
||||
<div v-for="(service, idx) in resource[item]" :key="idx">
|
||||
{{ service.name }} : {{ service.provider[0].name }}
|
||||
<div>
|
||||
<a-alert type="error" v-if="['vm', 'systemvm', 'router', 'ilbvm'].includes($route.meta.name) && 'hostcontrolstate' in resource && resource.hostcontrolstate !== 'Enabled'">
|
||||
<template #message>
|
||||
<div class="title">
|
||||
{{ $t('message.host.controlstate') }} {{ resource.hostcontrolstate }}. {{ $t('message.host.controlstate.retry') }}
|
||||
</div>
|
||||
</template>
|
||||
</a-alert>
|
||||
<a-list
|
||||
size="small"
|
||||
:dataSource="fetchDetails()">
|
||||
<a-list-item slot="renderItem" slot-scope="item" v-if="item in resource">
|
||||
<div>
|
||||
<strong>{{ item === 'service' ? $t('label.supportedservices') : $t('label.' + String(item).toLowerCase()) }}</strong>
|
||||
<br/>
|
||||
<div v-if="Array.isArray(resource[item]) && item === 'service'">
|
||||
<div v-for="(service, idx) in resource[item]" :key="idx">
|
||||
{{ service.name }} : {{ service.provider[0].name }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="$route.meta.name === 'backup' && item === 'volumes'">
|
||||
<div v-for="(volume, idx) in JSON.parse(resource[item])" :key="idx">
|
||||
<router-link :to="{ path: '/volume/' + volume.uuid }">{{ volume.type }} - {{ volume.path }}</router-link> ({{ parseFloat(volume.size / (1024.0 * 1024.0 * 1024.0)).toFixed(1) }} GB)
|
||||
<div v-else-if="$route.meta.name === 'backup' && item === 'volumes'">
|
||||
<div v-for="(volume, idx) in JSON.parse(resource[item])" :key="idx">
|
||||
<router-link :to="{ path: '/volume/' + volume.uuid }">{{ volume.type }} - {{ volume.path }}</router-link> ({{ parseFloat(volume.size / (1024.0 * 1024.0 * 1024.0)).toFixed(1) }} GB)
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="$route.meta.name === 'computeoffering' && item === 'rootdisksize'">
|
||||
<div>
|
||||
{{ resource.rootdisksize }} GB
|
||||
<div v-else-if="$route.meta.name === 'computeoffering' && item === 'rootdisksize'">
|
||||
<div>
|
||||
{{ resource.rootdisksize }} GB
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="['name', 'type'].includes(item)">
|
||||
<span v-if="['USER.LOGIN', 'USER.LOGOUT', 'ROUTER.HEALTH.CHECKS', 'FIREWALL.CLOSE', 'ALERT.SERVICE.DOMAINROUTER'].includes(resource[item])">{{ $t(resource[item].toLowerCase()) }}</span>
|
||||
<span v-else>{{ resource[item] }}</span>
|
||||
</div>
|
||||
<div v-else-if="['created', 'sent', 'lastannotated'].includes(item)">
|
||||
{{ $toLocaleDate(resource[item]) }}
|
||||
</div>
|
||||
<div v-else-if="$route.meta.name === 'userdata' && item === 'userdata'">
|
||||
<div style="white-space: pre-wrap;"> {{ decodeUserData(resource.userdata) }} </div>
|
||||
</div>
|
||||
<div v-else>{{ resource[item] }}</div>
|
||||
</div>
|
||||
<div v-else-if="['name', 'type'].includes(item)">
|
||||
<span v-if="['USER.LOGIN', 'USER.LOGOUT', 'ROUTER.HEALTH.CHECKS', 'FIREWALL.CLOSE', 'ALERT.SERVICE.DOMAINROUTER'].includes(resource[item])">{{ $t(resource[item].toLowerCase()) }}</span>
|
||||
<span v-else>{{ resource[item] }}</span>
|
||||
</a-list-item>
|
||||
<a-list-item slot="renderItem" slot-scope="item" v-else-if="item === 'ip6address' && ipV6Address && ipV6Address.length > 0">
|
||||
<div>
|
||||
<strong>{{ $t('label.' + String(item).toLowerCase()) }}</strong>
|
||||
<br/>
|
||||
<div>{{ ipV6Address }}</div>
|
||||
</div>
|
||||
<div v-else-if="['created', 'sent', 'lastannotated'].includes(item)">
|
||||
{{ $toLocaleDate(resource[item]) }}
|
||||
</div>
|
||||
<div v-else-if="$route.meta.name === 'userdata' && item === 'userdata'">
|
||||
<div style="white-space: pre-wrap;"> {{ decodeUserData(resource.userdata) }} </div>
|
||||
</div>
|
||||
<div v-else>{{ resource[item] }}</div>
|
||||
</div>
|
||||
</a-list-item>
|
||||
<a-list-item slot="renderItem" slot-scope="item" v-else-if="item === 'ip6address' && ipV6Address && ipV6Address.length > 0">
|
||||
<div>
|
||||
<strong>{{ $t('label.' + String(item).toLowerCase()) }}</strong>
|
||||
<br/>
|
||||
<div>{{ ipV6Address }}</div>
|
||||
</div>
|
||||
</a-list-item>
|
||||
<HostInfo :resource="resource" v-if="$route.meta.name === 'host' && 'listHosts' in $store.getters.apis" />
|
||||
<DedicateData :resource="resource" v-if="dedicatedSectionActive" />
|
||||
<VmwareData :resource="resource" v-if="$route.meta.name === 'zone' && 'listVmwareDcs' in $store.getters.apis" />
|
||||
</a-list>
|
||||
</a-list-item>
|
||||
<HostInfo :resource="resource" v-if="$route.meta.name === 'host' && 'listHosts' in $store.getters.apis" />
|
||||
<DedicateData :resource="resource" v-if="dedicatedSectionActive" />
|
||||
<VmwareData :resource="resource" v-if="$route.meta.name === 'zone' && 'listVmwareDcs' in $store.getters.apis" />
|
||||
</a-list>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
<a
|
||||
v-if="['vm', 'systemvm', 'router', 'ilbvm'].includes($route.meta.name) && 'updateVirtualMachine' in $store.getters.apis && 'createConsoleEndpoint' in $store.getters.apis"
|
||||
@click="consoleUrl">
|
||||
<a-button style="margin-left: 5px" shape="circle" type="dashed" :size="size" :disabled="['Stopped', 'Error', 'Destroyed'].includes(resource.state)" >
|
||||
<a-button style="margin-left: 5px" shape="circle" type="dashed" :size="size" :disabled="['Stopped', 'Error', 'Destroyed'].includes(resource.state) || resource.hostcontrolstate === 'Offline'" >
|
||||
<a-icon type="code" />
|
||||
</a-button>
|
||||
</a>
|
||||
|
|
|
|||
|
|
@ -66,7 +66,7 @@ export default {
|
|||
return fields
|
||||
},
|
||||
searchFilters: ['name', 'zoneid', 'domainid', 'account', 'tags'],
|
||||
details: ['displayname', 'name', 'id', 'state', 'ipaddress', 'ip6address', 'templatename', 'ostypename', 'serviceofferingname', 'isdynamicallyscalable', 'haenable', 'hypervisor', 'boottype', 'bootmode', 'account', 'domain', 'zonename', 'userdataid', 'userdataname', 'userdataparams', 'userdatadetails', 'userdatapolicy'],
|
||||
details: ['displayname', 'name', 'id', 'state', 'ipaddress', 'ip6address', 'templatename', 'ostypename', 'serviceofferingname', 'isdynamicallyscalable', 'haenable', 'hypervisor', 'boottype', 'bootmode', 'account', 'domain', 'zonename', 'userdataid', 'userdataname', 'userdataparams', 'userdatadetails', 'userdatapolicy', 'hostcontrolstate'],
|
||||
tabs: [{
|
||||
component: () => import('@/views/compute/InstanceTab.vue')
|
||||
}],
|
||||
|
|
@ -121,6 +121,7 @@ export default {
|
|||
docHelp: 'adminguide/virtual_machines.html#stopping-and-starting-vms',
|
||||
dataView: true,
|
||||
show: (record) => { return ['Running'].includes(record.state) },
|
||||
disabled: (record) => { return record.hostcontrolstate === 'Offline' },
|
||||
args: (record, store) => {
|
||||
var fields = []
|
||||
fields.push('forced')
|
||||
|
|
@ -148,6 +149,7 @@ export default {
|
|||
value: (record) => { return record.id }
|
||||
}
|
||||
},
|
||||
disabled: (record) => { return record.hostcontrolstate === 'Offline' },
|
||||
successMethod: (obj, result) => {
|
||||
const vm = result.jobresult.virtualmachine || {}
|
||||
if (result.jobstatus === 1 && vm.password) {
|
||||
|
|
@ -172,6 +174,7 @@ export default {
|
|||
(['Stopped'].includes(record.state) && ((record.hypervisor !== 'KVM' && record.hypervisor !== 'LXC') ||
|
||||
(record.hypervisor === 'KVM' && record.pooltype === 'PowerFlex'))))
|
||||
},
|
||||
disabled: (record) => { return record.hostcontrolstate === 'Offline' && record.hypervisor === 'KVM' },
|
||||
mapping: {
|
||||
virtualmachineid: {
|
||||
value: (record, params) => { return record.id }
|
||||
|
|
@ -189,6 +192,7 @@ export default {
|
|||
return ((['Running'].includes(record.state) && record.hypervisor !== 'LXC') ||
|
||||
(['Stopped'].includes(record.state) && !['KVM', 'LXC'].includes(record.hypervisor)))
|
||||
},
|
||||
disabled: (record) => { return record.hostcontrolstate === 'Offline' && record.hypervisor === 'KVM' },
|
||||
component: () => import('@/views/compute/CreateSnapshotWizard.vue')
|
||||
},
|
||||
{
|
||||
|
|
@ -262,6 +266,7 @@ export default {
|
|||
dataView: true,
|
||||
popup: true,
|
||||
show: (record) => { return ['Running', 'Stopped'].includes(record.state) && !record.isoid },
|
||||
disabled: (record) => { return record.hostcontrolstate === 'Offline' || record.hostcontrolstate === 'Maintenance' },
|
||||
component: () => import('@/views/compute/AttachIso.vue')
|
||||
},
|
||||
{
|
||||
|
|
@ -278,6 +283,7 @@ export default {
|
|||
return args
|
||||
},
|
||||
show: (record) => { return ['Running', 'Stopped'].includes(record.state) && 'isoid' in record && record.isoid },
|
||||
disabled: (record) => { return record.hostcontrolstate === 'Offline' || record.hostcontrolstate === 'Maintenance' },
|
||||
mapping: {
|
||||
virtualmachineid: {
|
||||
value: (record, params) => { return record.id }
|
||||
|
|
@ -313,6 +319,7 @@ export default {
|
|||
docHelp: 'adminguide/virtual_machines.html#moving-vms-between-hosts-manual-live-migration',
|
||||
dataView: true,
|
||||
show: (record, store) => { return ['Running'].includes(record.state) && ['Admin'].includes(store.userInfo.roletype) },
|
||||
disabled: (record) => { return record.hostcontrolstate === 'Offline' },
|
||||
popup: true,
|
||||
component: () => import('@/views/compute/MigrateWizard')
|
||||
},
|
||||
|
|
@ -324,6 +331,7 @@ export default {
|
|||
docHelp: 'adminguide/virtual_machines.html#moving-vms-between-hosts-manual-live-migration',
|
||||
dataView: true,
|
||||
show: (record, store) => { return ['Stopped'].includes(record.state) && ['Admin'].includes(store.userInfo.roletype) },
|
||||
disabled: (record) => { return record.hostcontrolstate === 'Offline' },
|
||||
component: () => import('@/views/compute/MigrateVMStorage'),
|
||||
popup: true
|
||||
},
|
||||
|
|
|
|||
|
|
@ -22,7 +22,7 @@ export default {
|
|||
permission: ['listInternalLoadBalancerVMs'],
|
||||
params: { projectid: '-1' },
|
||||
columns: ['name', 'state', 'publicip', 'guestnetworkname', 'vpcname', 'version', 'hostname', 'account', 'zonename', 'requiresupgrade'],
|
||||
details: ['name', 'id', 'version', 'requiresupgrade', 'guestnetworkname', 'vpcname', 'publicip', 'guestipaddress', 'linklocalip', 'serviceofferingname', 'networkdomain', 'isredundantrouter', 'redundantstate', 'hostname', 'account', 'zonename', 'created'],
|
||||
details: ['name', 'id', 'version', 'requiresupgrade', 'guestnetworkname', 'vpcname', 'publicip', 'guestipaddress', 'linklocalip', 'serviceofferingname', 'networkdomain', 'isredundantrouter', 'redundantstate', 'hostname', 'account', 'zonename', 'created', 'hostcontrolstate'],
|
||||
actions: [
|
||||
{
|
||||
api: 'startInternalLoadBalancerVM',
|
||||
|
|
@ -52,6 +52,7 @@ export default {
|
|||
label: 'label.action.migrate.router',
|
||||
dataView: true,
|
||||
show: (record, store) => { return record.state === 'Running' && ['Admin'].includes(store.userInfo.roletype) },
|
||||
disabled: (record) => { return record.hostcontrolstate === 'Offline' },
|
||||
component: () => import('@/views/compute/MigrateWizard'),
|
||||
popup: true
|
||||
},
|
||||
|
|
@ -61,6 +62,7 @@ export default {
|
|||
label: 'label.action.migrate.systemvm.to.ps',
|
||||
dataView: true,
|
||||
show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware'].includes(record.hypervisor) },
|
||||
disabled: (record) => { return record.hostcontrolstate === 'Offline' },
|
||||
component: () => import('@/views/compute/MigrateVMStorage'),
|
||||
popup: true
|
||||
}
|
||||
|
|
|
|||
|
|
@ -26,7 +26,7 @@ export default {
|
|||
params: { projectid: '-1' },
|
||||
columns: ['name', 'state', 'publicip', 'guestnetworkname', 'vpcname', 'redundantstate', 'version', 'hostname', 'account', 'zonename', 'requiresupgrade'],
|
||||
searchFilters: ['name', 'zoneid', 'podid', 'clusterid'],
|
||||
details: ['name', 'id', 'version', 'requiresupgrade', 'guestnetworkname', 'vpcname', 'publicip', 'guestipaddress', 'linklocalip', 'serviceofferingname', 'networkdomain', 'isredundantrouter', 'redundantstate', 'hostname', 'account', 'zonename', 'created'],
|
||||
details: ['name', 'id', 'version', 'requiresupgrade', 'guestnetworkname', 'vpcname', 'publicip', 'guestipaddress', 'linklocalip', 'serviceofferingname', 'networkdomain', 'isredundantrouter', 'redundantstate', 'hostname', 'account', 'zonename', 'created', 'hostcontrolstate'],
|
||||
resourceType: 'VirtualRouter',
|
||||
tabs: [{
|
||||
name: 'details',
|
||||
|
|
@ -127,6 +127,7 @@ export default {
|
|||
message: 'message.migrate.router.confirm',
|
||||
dataView: true,
|
||||
show: (record, store) => { return record.state === 'Running' && ['Admin'].includes(store.userInfo.roletype) },
|
||||
disabled: (record) => { return record.hostcontrolstate === 'Offline' },
|
||||
component: () => import('@/views/compute/MigrateWizard'),
|
||||
popup: true
|
||||
},
|
||||
|
|
@ -136,6 +137,7 @@ export default {
|
|||
label: 'label.action.migrate.systemvm.to.ps',
|
||||
dataView: true,
|
||||
show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware'].includes(record.hypervisor) },
|
||||
disabled: (record) => { return record.hostcontrolstate === 'Offline' },
|
||||
component: () => import('@/views/compute/MigrateVMStorage'),
|
||||
popup: true
|
||||
},
|
||||
|
|
|
|||
|
|
@ -24,7 +24,7 @@ export default {
|
|||
docHelp: 'adminguide/systemvm.html',
|
||||
permission: ['listSystemVms'],
|
||||
columns: ['name', 'state', 'agentstate', 'systemvmtype', 'publicip', 'privateip', 'linklocalip', 'hostname', 'zonename'],
|
||||
details: ['name', 'id', 'agentstate', 'systemvmtype', 'publicip', 'privateip', 'linklocalip', 'gateway', 'hostname', 'zonename', 'created', 'activeviewersessions', 'isdynamicallyscalable'],
|
||||
details: ['name', 'id', 'agentstate', 'systemvmtype', 'publicip', 'privateip', 'linklocalip', 'gateway', 'hostname', 'zonename', 'created', 'activeviewersessions', 'isdynamicallyscalable', 'hostcontrolstate'],
|
||||
resourceType: 'SystemVm',
|
||||
tabs: [
|
||||
{
|
||||
|
|
@ -100,6 +100,7 @@ export default {
|
|||
message: 'message.migrate.systemvm.confirm',
|
||||
dataView: true,
|
||||
show: (record, store) => { return record.state === 'Running' && ['Admin'].includes(store.userInfo.roletype) },
|
||||
disabled: (record) => { return record.hostcontrolstate === 'Offline' },
|
||||
component: () => import('@/views/compute/MigrateWizard'),
|
||||
popup: true
|
||||
},
|
||||
|
|
@ -109,6 +110,7 @@ export default {
|
|||
label: 'label.action.migrate.systemvm.to.ps',
|
||||
dataView: true,
|
||||
show: (record, store) => { return ['Stopped'].includes(record.state) && ['VMware'].includes(record.hypervisor) },
|
||||
disabled: (record) => { return record.hostcontrolstate === 'Offline' },
|
||||
component: () => import('@/views/compute/MigrateVMStorage'),
|
||||
popup: true
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in New Issue