diff --git a/api/src/main/java/com/cloud/host/ControlState.java b/api/src/main/java/com/cloud/host/ControlState.java new file mode 100644 index 00000000000..335125dde20 --- /dev/null +++ b/api/src/main/java/com/cloud/host/ControlState.java @@ -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; + } + } +} 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 83fcad54e83..1d4bb98fb85 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -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"; diff --git a/api/src/main/java/org/apache/cloudstack/api/response/DomainRouterResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/DomainRouterResponse.java index 66f40307449..0f63561e382 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/DomainRouterResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/DomainRouterResponse.java @@ -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; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java index ce2b406d15f..69b9b4cad9c 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/SystemVmResponse.java @@ -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; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java index 17b577bf4cb..6e1c5ae0616 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/UserVmResponse.java @@ -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; } diff --git a/api/src/test/java/com/cloud/host/ControlStateTest.java b/api/src/test/java/com/cloud/host/ControlStateTest.java new file mode 100644 index 00000000000..7b27d4c7574 --- /dev/null +++ b/api/src/test/java/com/cloud/host/ControlStateTest.java @@ -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); + } + +} diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41600to41610.sql b/engine/schema/src/main/resources/META-INF/db/schema-41600to41610.sql index 4d0f3f20803..56a0d3627cb 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41600to41610.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41600to41610.sql @@ -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; diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index 8c58ab6822e..a713bdce748 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -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) { diff --git a/server/src/main/java/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java b/server/src/main/java/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java index 96c129ad068..ed8a9266740 100644 --- a/server/src/main/java/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java +++ b/server/src/main/java/com/cloud/api/query/dao/DomainRouterJoinDaoImpl.java @@ -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 - - -
- {{ item === 'service' ? $t('label.supportedservices') : $t('label.' + String(item).toLowerCase()) }} -
-
-
- {{ service.name }} : {{ service.provider[0].name }} +
+ + + + + +
+ {{ item === 'service' ? $t('label.supportedservices') : $t('label.' + String(item).toLowerCase()) }} +
+
+
+ {{ service.name }} : {{ service.provider[0].name }} +
-
-
-
- {{ volume.type }} - {{ volume.path }} ({{ parseFloat(volume.size / (1024.0 * 1024.0 * 1024.0)).toFixed(1) }} GB) +
+
+ {{ volume.type }} - {{ volume.path }} ({{ parseFloat(volume.size / (1024.0 * 1024.0 * 1024.0)).toFixed(1) }} GB) +
-
-
-
- {{ resource.rootdisksize }} GB +
+
+ {{ resource.rootdisksize }} GB +
+
+ {{ $t(resource[item].toLowerCase()) }} + {{ resource[item] }} +
+
+ {{ $toLocaleDate(resource[item]) }} +
+
+
{{ decodeUserData(resource.userdata) }}
+
+
{{ resource[item] }}
-
- {{ $t(resource[item].toLowerCase()) }} - {{ resource[item] }} + + +
+ {{ $t('label.' + String(item).toLowerCase()) }} +
+
{{ ipV6Address }}
-
- {{ $toLocaleDate(resource[item]) }} -
-
-
{{ decodeUserData(resource.userdata) }}
-
-
{{ resource[item] }}
-
- - -
- {{ $t('label.' + String(item).toLowerCase()) }} -
-
{{ ipV6Address }}
-
-
- - - - + + + + + +