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 96ed750852e..3cb937e8427 100644 --- a/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java +++ b/api/src/main/java/org/apache/cloudstack/api/ApiConstants.java @@ -203,6 +203,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 a5fa2bd08c2..99e5f6ccdfa 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; @@ -302,6 +306,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 108e480deb0..f2903b2626c 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; @@ -461,6 +465,10 @@ public class UserVmResponse extends BaseResponseWithTagInformation implements Co return hostName; } + public String getHostControlState() { + return hostControlState; + } + public String getTemplateId() { return templateId; } @@ -703,6 +711,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..2e8b38cd54a --- /dev/null +++ b/api/src/test/java/com/cloud/host/ControlStateTest.java @@ -0,0 +1,109 @@ +// 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 testHostControlState1() { + // 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); + } + @Test + public void testHostControlState2() { + // 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); + } + + @Test + public void testHostControlState3() { + // 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 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); + } + + @Test + public void testHostControlState4() { + // 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); + } + + @Test + public void testHostControlState5() { + // 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-41720to41800.sql b/engine/schema/src/main/resources/META-INF/db/schema-41720to41800.sql index d1180c8f2c2..c3a18ec7e2d 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41720to41800.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41720to41800.sql @@ -65,6 +65,8 @@ CREATE VIEW `cloud`.`domain_router_view` AS 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, @@ -744,6 +746,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`, diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index c7cfda4fc67..f6d30d52dfa 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -37,6 +37,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 com.cloud.api.query.dao.UserVmJoinDao; @@ -1549,6 +1550,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()); } } 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 feeaa8b952a..83a89622bd2 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 @@ -38,6 +38,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; @@ -135,6 +136,7 @@ public class DomainRouterJoinDaoImpl extends GenericDaoBase + + +