From 24c56dcaf4e64c02f23d47f7640735aa95ceb4d9 Mon Sep 17 00:00:00 2001 From: rtodirica Date: Mon, 6 Jul 2020 17:18:22 +0300 Subject: [PATCH 01/62] WIP - Integrate tungsten with cloudstack --- .../main/java/com/cloud/event/EventTypes.java | 6 + client/pom.xml | 12 +- .../tungsten/conf/tungsten.properties | 19 ++ plugins/network-elements/tungsten/pom.xml | 157 +++++++++ .../command/CreateTungstenInstanceIpCmd.java | 124 ++++++++ .../api/command/CreateTungstenNetworkCmd.java | 175 ++++++++++ .../CreateTungstenVirtualMachineCmd.java | 104 ++++++ .../command/CreateTungstenVmInterfaceCmd.java | 135 ++++++++ .../api/command/DeleteTungstenNetworkCmd.java | 63 ++++ .../api/command/ListTungstenNetworkCmd.java | 53 ++++ .../ListTungstenVirtualMachineCmd.java | 54 ++++ .../command/ListTungstenVmInterfaceCmd.java | 54 ++++ .../response/TungstenInstanceIpResponse.java | 22 ++ .../api/response/TungstenNetworkResponse.java | 91 ++++++ .../TungstenVirtualMachineResponse.java | 50 +++ .../response/TungstenVmInterfaceResponse.java | 73 +++++ .../tungsten/service/TungstenManager.java | 34 ++ .../tungsten/service/TungstenManagerImpl.java | 299 ++++++++++++++++++ .../service/TungstenResponseHelper.java | 67 ++++ .../cloudstack/tungsten/module.properties | 21 ++ .../tungsten/spring-tungsten-context.xml | 32 ++ plugins/pom.xml | 1 + tools/apidoc/gen_toc.py | 4 + 23 files changed, 1649 insertions(+), 1 deletion(-) create mode 100644 plugins/network-elements/tungsten/conf/tungsten.properties create mode 100644 plugins/network-elements/tungsten/pom.xml create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenInstanceIpCmd.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenNetworkCmd.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenVirtualMachineCmd.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenVmInterfaceCmd.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenNetworkCmd.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenNetworkCmd.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenVirtualMachineCmd.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenVmInterfaceCmd.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenInstanceIpResponse.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenNetworkResponse.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenVirtualMachineResponse.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenVmInterfaceResponse.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java create mode 100644 plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/module.properties create mode 100644 plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/spring-tungsten-context.xml diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java index ac7a612a2029..9df1fc47c1c5 100644 --- a/api/src/main/java/com/cloud/event/EventTypes.java +++ b/api/src/main/java/com/cloud/event/EventTypes.java @@ -161,6 +161,12 @@ public class EventTypes { public static final String EVENT_FIREWALL_EGRESS_CLOSE = "FIREWALL.EGRESS.CLOSE"; public static final String EVENT_FIREWALL_EGRESS_UPDATE = "FIREWALL.EGRESS.UPDATE"; + //Tungsten + public static final String EVENT_TUNGSTEN_VM_INTERFACE_CREATE = "TUNGSTEN.VM.INTERFACE.CREATE"; + public static final String EVENT_TUNGSTEN_VIRTUAL_MACHINE_CREATE = "TUNGSTEN.VIRTUAL.MACHINE.CREATE"; + public static final String EVENT_TUNGSTEN_NETWORK_CREATE = "TUNGSTEN.NETWORK.CREATE"; + public static final String EVENT_TUNGSTEN_INSTANCE_IP = "TUNGSTEN.INSTANCE.IP"; + //NIC Events public static final String EVENT_NIC_CREATE = "NIC.CREATE"; public static final String EVENT_NIC_DELETE = "NIC.DELETE"; diff --git a/client/pom.xml b/client/pom.xml index 921a4adbf88b..d444dade91b9 100644 --- a/client/pom.xml +++ b/client/pom.xml @@ -30,7 +30,7 @@ juniper-contrail - https://juniper.github.io/contrail-maven/snapshots + https://github.com/Juniper/contrail-maven/raw/master/releases @@ -202,6 +202,11 @@ cloud-plugin-network-ovs ${project.version} + + org.apache.cloudstack + cloud-plugin-network-tungsten + ${project.version} + org.apache.cloudstack cloud-plugin-network-elb @@ -513,6 +518,11 @@ cloud-plugin-integrations-kubernetes-service ${project.version} + + net.juniper.contrail + juniper-contrail-api + 1.2 + diff --git a/plugins/network-elements/tungsten/conf/tungsten.properties b/plugins/network-elements/tungsten/conf/tungsten.properties new file mode 100644 index 000000000000..30a89c610eca --- /dev/null +++ b/plugins/network-elements/tungsten/conf/tungsten.properties @@ -0,0 +1,19 @@ +# 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. + +tungsten.api.hostname=10.102.12.239 +tungsten.api.port=8082 diff --git a/plugins/network-elements/tungsten/pom.xml b/plugins/network-elements/tungsten/pom.xml new file mode 100644 index 000000000000..24eee731e424 --- /dev/null +++ b/plugins/network-elements/tungsten/pom.xml @@ -0,0 +1,157 @@ + + + 4.0.0 + cloud-plugin-network-tungsten + Apache CloudStack Plugin - Tungsten Network + + + org.apache.cloudstack + cloudstack-plugins + 4.15.0.0-SNAPSHOT + ../../pom.xml + + + + + juniper-contrail + https://github.com/Juniper/contrail-maven/raw/master/releases + + + + + + org.apache.cloudstack + cloud-api + ${project.version} + + + org.apache.cloudstack + cloud-server + ${project.version} + + + org.apache.cloudstack + cloud-plugin-hypervisor-xenserver + ${project.version} + test + + + org.apache.cloudstack + cloud-plugin-network-internallb + ${project.version} + + + org.apache.cloudstack + cloud-engine-orchestration + ${project.version} + test + + + org.apache.cloudstack + cloud-engine-api + ${project.version} + + + org.apache.cloudstack + cloud-engine-schema + ${project.version} + + + org.apache.cloudstack + cloud-framework-config + ${project.version} + + + org.apache.cloudstack + cloud-framework-events + ${project.version} + + + org.apache.cloudstack + cloud-utils + ${project.version} + + + xml-apis + xml-apis + + + + + org.apache.cloudstack + cloud-framework-spring-lifecycle + ${project.version} + test + + + org.eclipse.jetty + jetty-security + ${cs.jetty.version} + test + + + com.google.guava + guava + + + net.juniper.contrail + juniper-contrail-api + 1.2 + + + mysql + mysql-connector-java + provided + + + org.apache.commons + commons-exec + + + + + + + maven-antrun-plugin + + + generate-resource + generate-resources + + run + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenInstanceIpCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenInstanceIpCmd.java new file mode 100644 index 000000000000..9f4ded0c974e --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenInstanceIpCmd.java @@ -0,0 +1,124 @@ +package org.apache.cloudstack.network.tungsten.api.command; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import net.juniper.contrail.api.types.InstanceIp; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCreateCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.ProjectResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.network.tungsten.api.response.TungstenInstanceIpResponse; +import org.apache.cloudstack.network.tungsten.service.TungstenManager; +import org.apache.cloudstack.network.tungsten.service.TungstenResponseHelper; + +import javax.inject.Inject; +import java.io.IOException; + +@APICommand(name = "createTungstenInstanceIp", + description = "Create tungsten instance ip", + responseObject = TungstenInstanceIpResponse.class) +public class CreateTungstenInstanceIpCmd extends BaseAsyncCreateCmd { + + private static final String s_name = "createtungsteninstanceipresponse"; + + //Owner information + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "An optional account for the virtual machine. Must be used with domainId.") + private String accountName; + + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.UUID, + entityType = DomainResponse.class, + description = "An optional domainId for the virtual machine. If the account parameter is used, domainId must also be used.") + private Long domainId; + + @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "Project ID for the service instance") + private Long projectId; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Tungsten network Name") + private String name; + + @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_UUID, type = CommandType.STRING, description = "Tungsten Network UUID") + private String tungstenNetworkUuid; + + @Parameter(name = ApiConstants.TUNGSTEN_VM_INTERFACE_UUID, type = CommandType.STRING, description = "Tungsten Virtual Machine Interface UUID") + private String tungstenVmInterfaceUuid; + + @Parameter(name = ApiConstants.TUNGSTEN_INSTANCE_IP_ADDRESS, type = CommandType.STRING, description = "Tungsten Instance IP Address") + private String tungstenInstanceIpAddress; + + public String getName() { + return name; + } + + public String getTungstenNetworkUuid() { + return tungstenNetworkUuid; + } + + public String getTungstenVmInterfaceUuid() { + return tungstenVmInterfaceUuid; + } + + public String getTungstenInstanceIpAddress() { + return tungstenInstanceIpAddress; + } + + @Inject + TungstenManager tungstenManager; + + @Override + public void create() throws ResourceAllocationException { + InstanceIp instanceIp = tungstenManager.createInstanceIp(this); + if(instanceIp != null) { + setEntityId(1L); + setEntityUuid(instanceIp.getUuid()); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create instance ip into tungsten."); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_TUNGSTEN_INSTANCE_IP; + } + + @Override + public String getEventDescription() { + return "Create tungsten instance ip"; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try { + InstanceIp instanceIp = (InstanceIp) tungstenManager.getTungstenObjectByUUID(InstanceIp.class, getEntityUuid()); + TungstenInstanceIpResponse response = TungstenResponseHelper.createTungstenInstanceIpResponse(instanceIp); + response.setResponseName(getCommandName()); + setResponseObject(response); + } catch (IOException e) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create instance ip into tungsten."); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true); + if (accountId == null) { + return CallContext.current().getCallingAccount().getId(); + } + + return accountId; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenNetworkCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenNetworkCmd.java new file mode 100644 index 000000000000..25e093725a87 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenNetworkCmd.java @@ -0,0 +1,175 @@ +package org.apache.cloudstack.network.tungsten.api.command; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import net.juniper.contrail.api.types.VirtualNetwork; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCreateCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.ProjectResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.network.tungsten.api.response.TungstenNetworkResponse; +import org.apache.cloudstack.network.tungsten.service.TungstenManager; +import org.apache.cloudstack.network.tungsten.service.TungstenResponseHelper; + +import javax.inject.Inject; +import java.io.IOException; +import java.util.List; + +@APICommand(name = "createTungstenNetwork", + description = "Create tungsten network", + responseObject = TungstenNetworkResponse.class) +public class CreateTungstenNetworkCmd extends BaseAsyncCreateCmd { + + private static final String s_name = "createtungstennetworkresponse"; + + //Owner information + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "An optional account for the virtual machine. Must be used with domainId.") + private String accountName; + + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.UUID, + entityType = DomainResponse.class, + description = "An optional domainId for the virtual machine. If the account parameter is used, domainId must also be used.") + private Long domainId; + + @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "Project ID for the service instance") + private Long projectId; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Tungsten network Name") + private String name; + + @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_IPAM_UUID, type = CommandType.STRING, description = "Network Ipam UUID") + private String networkIpamUUID; + + @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_SUBNET_IP_PREFIX, type = CommandType.STRING, description = "Subnet ip prefix") + private String subnetIpPrefix; + + @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_SUBNET_IP_PREFIX_LEN, type = CommandType.INTEGER, description = "Subnet ip prefix length") + private int subnetIpPrefixLength; + + @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_DEFAULT_GATEWAY, type = CommandType.STRING, description = "Tungsten network default gateway") + private String defaultGateway; + + @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_ENABLE_DHC, type = CommandType.BOOLEAN, description = "Tungsten network enable dhcp") + private boolean enableDHCP; + + @Parameter(name = ApiConstants.TUNGSTEN_DNS_NAME_SERVERS, type = CommandType.LIST, description = "Tungsten network DNS name servers") + private List dnsNameservers; + + @Parameter(name = ApiConstants.TUNGSTEN_IP_ALLOC_POOL_START, type = CommandType.STRING, description = "Tungsten network ip allocation pool start") + private String ipAllocPoolStart; + + @Parameter(name = ApiConstants.TUNGSTEN_IP_ALLOC_POOL_END, type = CommandType.STRING, description = "Tungsten network ip allocation pool end") + private String ipAllocPoolEnd; + + @Parameter(name = ApiConstants.TUNGSTEN_ADDR_FROM_START, type = CommandType.BOOLEAN, description = "Subnet ip prefix") + private boolean addrFromStart; + + @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_SUBNET_NAME, type = CommandType.STRING, description = "Tungsten network subnet name") + private String subnetName; + + + public String getName() { + return name; + } + + public String getNetworkIpamUUID() { + return networkIpamUUID; + } + + public String getSubnetIpPrefix() { + return subnetIpPrefix; + } + + public int getSubnetIpPrefixLength() { + return subnetIpPrefixLength; + } + + public String getDefaultGateway() { + return defaultGateway; + } + + public boolean isEnableDHCP() { + return enableDHCP; + } + + public List getDnsNameservers() { + return dnsNameservers; + } + + public String getIpAllocPoolStart() { + return ipAllocPoolStart; + } + + public String getIpAllocPoolEnd() { + return ipAllocPoolEnd; + } + + public boolean isAddrFromStart() { + return addrFromStart; + } + + public String getSubnetName() { + return subnetName; + } + + @Inject + TungstenManager tungstenManager; + + @Override + public void create() throws ResourceAllocationException { + VirtualNetwork network = tungstenManager.createTungstenNetwork(this); + if(network != null) { + setEntityId(1L); + setEntityUuid(network.getUuid()); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create network into tungsten."); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_TUNGSTEN_NETWORK_CREATE; + } + + @Override + public String getEventDescription() { + return "Create tungsten network"; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try { + VirtualNetwork network = (VirtualNetwork) tungstenManager.getTungstenObjectByUUID(VirtualNetwork.class, getEntityUuid()); + TungstenNetworkResponse response = TungstenResponseHelper.createTungstenNetworkResponse(network); + response.setResponseName(getCommandName()); + setResponseObject(response); + } catch (IOException e) { + e.printStackTrace(); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true); + if (accountId == null) { + return CallContext.current().getCallingAccount().getId(); + } + + return accountId; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenVirtualMachineCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenVirtualMachineCmd.java new file mode 100644 index 000000000000..facfe9c79007 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenVirtualMachineCmd.java @@ -0,0 +1,104 @@ +package org.apache.cloudstack.network.tungsten.api.command; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import net.juniper.contrail.api.types.VirtualMachine; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCreateCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.ProjectResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.network.tungsten.api.response.TungstenVirtualMachineResponse; +import org.apache.cloudstack.network.tungsten.service.TungstenManager; +import org.apache.cloudstack.network.tungsten.service.TungstenResponseHelper; + +import javax.inject.Inject; +import java.io.IOException; + +@APICommand(name = "createTungstenVirtualMachine", + description = "Create tungsten virtual machine", + responseObject = TungstenVirtualMachineResponse.class) +public class CreateTungstenVirtualMachineCmd extends BaseAsyncCreateCmd { + + private static final String s_name = "createtungstenvirtualmachineresponse"; + + //Owner information + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "An optional account for the virtual machine. Must be used with domainId.") + private String accountName; + + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.UUID, + entityType = DomainResponse.class, + description = "An optional domainId for the virtual machine. If the account parameter is used, domainId must also be used.") + private Long domainId; + + @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "Project ID for the service instance") + private Long projectId; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Tungsten virtual machine interface name") + private String name; + + public String getName() { + return name; + } + + @Inject + TungstenManager tungstenManager; + + @Override + public void create() throws ResourceAllocationException { + VirtualMachine virtualMachine = tungstenManager.createTungstenVirtualMachine(this); + if(virtualMachine != null) { + setEntityId(1L); + setEntityUuid(virtualMachine.getUuid()); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create virtual machine into tungsten."); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_TUNGSTEN_VIRTUAL_MACHINE_CREATE; + } + + @Override + public String getEventDescription() { + return "Create tungsten virtual machine"; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try{ + VirtualMachine virtualMachine = (VirtualMachine) tungstenManager.getTungstenObjectByUUID(VirtualMachine.class, getEntityUuid()); + TungstenVirtualMachineResponse response = TungstenResponseHelper.createTungstenVirtualMachineResponse(virtualMachine); + response.setResponseName(getCommandName()); + setResponseObject(response); + } catch (IOException e) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create virtual machine into tungsten."); + } + + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true); + if (accountId == null) { + return CallContext.current().getCallingAccount().getId(); + } + + return accountId; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenVmInterfaceCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenVmInterfaceCmd.java new file mode 100644 index 000000000000..e58f08cd3769 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenVmInterfaceCmd.java @@ -0,0 +1,135 @@ +package org.apache.cloudstack.network.tungsten.api.command; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import net.juniper.contrail.api.types.VirtualMachineInterface; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCreateCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.ProjectResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.network.tungsten.api.response.TungstenVmInterfaceResponse; +import org.apache.cloudstack.network.tungsten.service.TungstenManager; +import org.apache.cloudstack.network.tungsten.service.TungstenResponseHelper; + +import javax.inject.Inject; +import java.io.IOException; +import java.util.List; + +@APICommand(name = "createTungstenVmInterface", + description = "Create tungsten virtual machine interface", + responseObject = TungstenVmInterfaceResponse.class) +public class CreateTungstenVmInterfaceCmd extends BaseAsyncCreateCmd { + + private static final String s_name = "createtungstenvminterfaceresponse"; + + //Owner information + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "An optional account for the virtual machine. Must be used with domainId.") + private String accountName; + + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.UUID, + entityType = DomainResponse.class, + description = "An optional domainId for the virtual machine. If the account parameter is used, domainId must also be used.") + private Long domainId; + + @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "Project ID for the service instance") + private Long projectId; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Tungsten virtual machine interface name") + private String name; + + @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_UUID, type = CommandType.STRING, description = "Tungsten Network UUID") + private String tungstenNetworkUuid; + + @Parameter(name = ApiConstants.TUNGSTEN_VIRTUAL_MACHINE_UUID, type = CommandType.STRING, description = "Tungsten virtual machine UUID") + private String tungstenVirtualMachineUuid; + + @Parameter(name = ApiConstants.TUNGSTEN_SECURITY_GROUP_UUID, type = CommandType.STRING, description = "Tungsten security group UUID") + private String tungstenSecurityGroupUuid; + + @Parameter(name = ApiConstants.TUNGSTEN_PROJECT_UUID, type = CommandType.STRING, description = "Tungsten project UUID") + private String tungstenProjectUuid; + + @Parameter(name = ApiConstants.TUNGSTEN_VM_INTERFACE_MAC_ADDRESSES, type = CommandType.LIST, collectionType = CommandType.STRING, description = "Tungsten virtual machine interface mac addresses") + private List tungstenVmInterfaceMacAddresses; + + public String getName() { + return name; + } + + public String getTungstenNetworkUuid() { + return tungstenNetworkUuid; + } + + public String getTungstenVirtualMachineUuid() { + return tungstenVirtualMachineUuid; + } + + public String getTungstenSecurityGroupUuid() { + return tungstenSecurityGroupUuid; + } + + public String getTungstenProjectUuid() { + return tungstenProjectUuid; + } + + public List getTungstenVmInterfaceMacAddresses() { + return tungstenVmInterfaceMacAddresses; + } + + @Inject + TungstenManager tungstenManager; + + @Override + public void create(){ + VirtualMachineInterface virtualMachineInterface = tungstenManager.createTungstenVirtualMachineInterface(this); + if(virtualMachineInterface != null) { + setEntityId(1L); + setEntityUuid(virtualMachineInterface.getUuid()); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create virtual machine interface into tungsten."); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_TUNGSTEN_VM_INTERFACE_CREATE; + } + + @Override + public String getEventDescription() { + return "Create tungsten virtual machine interface."; + } + + @Override + public void execute() throws ServerApiException, ConcurrentOperationException{ + try{ + VirtualMachineInterface virtualMachineInterface = (VirtualMachineInterface) tungstenManager.getTungstenObjectByUUID(VirtualMachineInterface.class, getEntityUuid()); + TungstenVmInterfaceResponse response = TungstenResponseHelper.createTungstenVmInterfaceResponse(virtualMachineInterface); + response.setResponseName(getCommandName()); + setResponseObject(response); + } catch (IOException e) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create virtual machine interface into tungsten."); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true); + if (accountId == null) { + return CallContext.current().getCallingAccount().getId(); + } + + return accountId; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenNetworkCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenNetworkCmd.java new file mode 100644 index 000000000000..b60742f7632e --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenNetworkCmd.java @@ -0,0 +1,63 @@ +package org.apache.cloudstack.network.tungsten.api.command; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.user.Account; +import net.juniper.contrail.api.types.VirtualNetwork; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.network.tungsten.service.TungstenManager; + +import javax.inject.Inject; +import java.io.IOException; + +@APICommand(name = "deleteTungstenNetwork", + description = "Delete tungstens networks", + responseObject = SuccessResponse.class) +public class DeleteTungstenNetworkCmd extends BaseCmd { + + private static final String s_name = "deletetungstennetworkresponse"; + + @Parameter(name= ApiConstants.UUID, type=CommandType.STRING, required=true, description="The UUID of the tungsten network") + private String uuid; + + public String getUuid() { + return uuid; + } + + @Inject + TungstenManager tungstenManager; + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try { + VirtualNetwork network = tungstenManager.deleteTungstenNetwork(this); + if(network != null){ + SuccessResponse response = new SuccessResponse(getCommandName()); + setResponseObject(response); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete tungsten network"); + } + } catch (IOException e) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete tungsten network"); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenNetworkCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenNetworkCmd.java new file mode 100644 index 000000000000..816b0e327f36 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenNetworkCmd.java @@ -0,0 +1,53 @@ +package org.apache.cloudstack.network.tungsten.api.command; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseListTaggedResourcesCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.user.UserCmd; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.network.tungsten.api.response.TungstenNetworkResponse; +import org.apache.cloudstack.network.tungsten.service.TungstenManager; + +import javax.inject.Inject; +import java.io.IOException; + +@APICommand(name = "listTungstenNetworks", + description = "List tungstens networks", + responseObject = TungstenNetworkResponse.class) +public class ListTungstenNetworkCmd extends BaseListTaggedResourcesCmd implements UserCmd { + + private static final String s_name = "listtungstennetworksresponse"; + + @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_UUID, type = CommandType.STRING, description = "list tungsten networks by uuid") + private String networkUUID; + + public String getNetworkUUID() { + return networkUUID; + } + + @Inject + TungstenManager tungstenManager; + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try{ + ListResponse response = tungstenManager.getNetworks(this); + response.setResponseName(getCommandName()); + setResponseObject(response); + } catch (IOException e) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to retrieve networks from tungsten."); + } + } + + public String getCommandName() { + return s_name; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenVirtualMachineCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenVirtualMachineCmd.java new file mode 100644 index 000000000000..e35e184fbd85 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenVirtualMachineCmd.java @@ -0,0 +1,54 @@ +package org.apache.cloudstack.network.tungsten.api.command; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseListTaggedResourcesCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.user.UserCmd; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.network.tungsten.api.response.TungstenVirtualMachineResponse; +import org.apache.cloudstack.network.tungsten.service.TungstenManager; + +import javax.inject.Inject; +import java.io.IOException; + +@APICommand(name = "listTungstenVirtualMachines", + description = "List tungsten virtual machines", + responseObject = TungstenVirtualMachineResponse.class) +public class ListTungstenVirtualMachineCmd extends BaseListTaggedResourcesCmd implements UserCmd { + + private static final String s_name = "listtungstenvirtualmachinesresponse"; + + @Parameter(name = ApiConstants.TUNGSTEN_VIRTUAL_MACHINE_UUID, type = CommandType.STRING, description = "list tungsten virtual machine by uuid") + private String virtualMachineUUID; + + public String getVirtualMachineUUID() { + return virtualMachineUUID; + } + + @Inject + TungstenManager tungstenManager; + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try{ + ListResponse response = tungstenManager.getVirtualMachines(this); + response.setResponseName(getCommandName()); + setResponseObject(response); + } catch (IOException e) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to retrieve virtual machines from tungsten."); + } + } + + @Override + public String getCommandName() { + return s_name; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenVmInterfaceCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenVmInterfaceCmd.java new file mode 100644 index 000000000000..236eeb4c164a --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenVmInterfaceCmd.java @@ -0,0 +1,54 @@ +package org.apache.cloudstack.network.tungsten.api.command; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseListTaggedResourcesCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.user.UserCmd; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.network.tungsten.api.response.TungstenVmInterfaceResponse; +import org.apache.cloudstack.network.tungsten.service.TungstenManager; + +import javax.inject.Inject; +import java.io.IOException; + +@APICommand(name = "listTungstenVmInterfaces", + description = "List tungsten virtual machine interfaces", + responseObject = TungstenVmInterfaceResponse.class) +public class ListTungstenVmInterfaceCmd extends BaseListTaggedResourcesCmd implements UserCmd { + + private static final String s_name = "listtungstenvminterfacesresponse"; + + @Parameter(name = ApiConstants.TUNGSTEN_VM_INTERFACE_UUID, type = CommandType.STRING, description = "list tungsten virtual machine interface by uuid") + private String vmInterfaceUUID; + + public String getVmInterfaceUUID() { + return vmInterfaceUUID; + } + + @Inject + TungstenManager tungstenManager; + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try{ + ListResponse response = tungstenManager.getVmInterfaces(this); + response.setResponseName(getCommandName()); + setResponseObject(response); + } catch (IOException e) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to retrieve virtual machine interfaces from tungsten."); + } + } + + @Override + public String getCommandName() { + return s_name; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenInstanceIpResponse.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenInstanceIpResponse.java new file mode 100644 index 000000000000..ea8a9ccf5dbb --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenInstanceIpResponse.java @@ -0,0 +1,22 @@ +package org.apache.cloudstack.network.tungsten.api.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +public class TungstenInstanceIpResponse extends BaseResponse { + + @SerializedName(ApiConstants.NAME) + @Param(description = "name of the tungsten network") + private String name; + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenNetworkResponse.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenNetworkResponse.java new file mode 100644 index 000000000000..519319269c21 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenNetworkResponse.java @@ -0,0 +1,91 @@ +package org.apache.cloudstack.network.tungsten.api.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import net.juniper.contrail.api.ApiObjectBase; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import java.util.List; + +public class TungstenNetworkResponse extends BaseResponse { + + @SerializedName(ApiConstants.UUID) + @Param(description = "UUID of the tungsten network") + private String uuid; + @SerializedName(ApiConstants.PARENT_UUID) + @Param(description = "parent_uuid of the tungsten network") + private String parentUuid; + @SerializedName(ApiConstants.NAME) + @Param(description = "name of the tungsten network") + private String name; + @SerializedName(ApiConstants.FQ_NAME) + @Param(description = "fq_name of the tungsten network") + private List fqName; + @SerializedName(ApiConstants.PARENT) + @Param(description = "parent of the tungsten network") + private ApiObjectBase parent; + @SerializedName(ApiConstants.PARENT_TYPE) + @Param(description = "parent_type of the tungsten network") + private String parentType; + @SerializedName(ApiConstants.TUNGSTEN_NETWORK_IPAM_UUID) + @Param(description = "tungsten network ipam uuid") + private String networkIpamUUID; + + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getParentUuid() { + return parentUuid; + } + + public void setParentUuid(String parentUuid) { + this.parentUuid = parentUuid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getFqName() { + return fqName; + } + + public void setFqName(List fqName) { + this.fqName = fqName; + } + + public ApiObjectBase getParent() { + return parent; + } + + public void setParent(ApiObjectBase parent) { + this.parent = parent; + } + + public String getParentType() { + return parentType; + } + + public void setParentType(String parentType) { + this.parentType = parentType; + } + + public String getNetworkIpamUUID() { + return networkIpamUUID; + } + + public void setNetworkIpamUUID(String networkIpamUUID) { + this.networkIpamUUID = networkIpamUUID; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenVirtualMachineResponse.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenVirtualMachineResponse.java new file mode 100644 index 000000000000..c1ad2fc6abd1 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenVirtualMachineResponse.java @@ -0,0 +1,50 @@ +package org.apache.cloudstack.network.tungsten.api.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import java.util.ArrayList; +import java.util.List; + +public class TungstenVirtualMachineResponse extends BaseResponse { + + @SerializedName(ApiConstants.UUID) + @Param(description = "UUID of the tungsten virtual machine") + private String uuid; + @SerializedName(ApiConstants.NAME) + @Param(description = "name of the tungsten virtual machine") + private String name; + @SerializedName(ApiConstants.TUNGSTEN_VM_INTERFACE_UUID) + @Param(description = "virtual machine interface uuid of the tungsten virtual machine") + private List vmInterfacesUuid; + + public TungstenVirtualMachineResponse(){ + vmInterfacesUuid = new ArrayList<>(); + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public List getVmInterfacesUuid() { + return vmInterfacesUuid; + } + + public void setVmInterfacesUuid(List vmInterfacesUuid) { + this.vmInterfacesUuid = vmInterfacesUuid; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenVmInterfaceResponse.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenVmInterfaceResponse.java new file mode 100644 index 000000000000..6372871b28fb --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenVmInterfaceResponse.java @@ -0,0 +1,73 @@ +package org.apache.cloudstack.network.tungsten.api.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +import java.util.ArrayList; +import java.util.List; + +public class TungstenVmInterfaceResponse extends BaseResponse{ + + @SerializedName(ApiConstants.UUID) + @Param(description = "UUID of the tungsten virtual machine interface") + private String uuid; + @SerializedName(ApiConstants.NAME) + @Param(description = "name of the tungsten virtual machine interface") + private String name; + @SerializedName(ApiConstants.PARENT_UUID) + @Param(description = "parent uuid of the tungsten virtual machine interface") + private String parentUuid; + @SerializedName(ApiConstants.TUNGSTEN_VIRTUAL_MACHINE_UUID) + @Param(description = "virtual machine uuid of the tungsten virtual machine interface") + private List virtualMachinesUuid; + @SerializedName(ApiConstants.TUNGSTEN_NETWORK_UUID) + @Param(description = "virtual network of the tungsten virtual machine interface") + private List virtualNetworksUuid; + + public TungstenVmInterfaceResponse(){ + virtualMachinesUuid = new ArrayList<>(); + virtualNetworksUuid = new ArrayList<>(); + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getParentUuid() { + return parentUuid; + } + + public void setParentUuid(String parentUuid) { + this.parentUuid = parentUuid; + } + + public List getVirtualMachinesUuid() { + return virtualMachinesUuid; + } + + public void setVirtualMachinesUuid(List virtualMachinesUuid) { + this.virtualMachinesUuid = virtualMachinesUuid; + } + + public List getVirtualNetworksUuid() { + return virtualNetworksUuid; + } + + public void setVirtualNetworksUuid(List virtualNetworksUuid) { + this.virtualNetworksUuid = virtualNetworksUuid; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java new file mode 100644 index 000000000000..78c4e4662427 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java @@ -0,0 +1,34 @@ +package org.apache.cloudstack.network.tungsten.service; + +import com.cloud.utils.component.PluggableService; +import net.juniper.contrail.api.ApiObjectBase; +import net.juniper.contrail.api.types.InstanceIp; +import net.juniper.contrail.api.types.VirtualMachine; +import net.juniper.contrail.api.types.VirtualMachineInterface; +import net.juniper.contrail.api.types.VirtualNetwork; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenInstanceIpCmd; +import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenNetworkCmd; +import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenVirtualMachineCmd; +import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenVmInterfaceCmd; +import org.apache.cloudstack.network.tungsten.api.command.DeleteTungstenNetworkCmd; +import org.apache.cloudstack.network.tungsten.api.command.ListTungstenNetworkCmd; +import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVirtualMachineCmd; +import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVmInterfaceCmd; +import org.apache.cloudstack.network.tungsten.api.response.TungstenNetworkResponse; +import org.apache.cloudstack.network.tungsten.api.response.TungstenVirtualMachineResponse; +import org.apache.cloudstack.network.tungsten.api.response.TungstenVmInterfaceResponse; + +import java.io.IOException; + +public interface TungstenManager extends PluggableService { + ListResponse getNetworks(ListTungstenNetworkCmd cmd) throws IOException; + ListResponse getVmInterfaces(ListTungstenVmInterfaceCmd cmd) throws IOException; + ListResponse getVirtualMachines(ListTungstenVirtualMachineCmd cmd) throws IOException; + VirtualNetwork createTungstenNetwork(CreateTungstenNetworkCmd cmd); + VirtualMachine createTungstenVirtualMachine(CreateTungstenVirtualMachineCmd cmd); + VirtualMachineInterface createTungstenVirtualMachineInterface(CreateTungstenVmInterfaceCmd cmd); + InstanceIp createInstanceIp(CreateTungstenInstanceIpCmd cmd); + VirtualNetwork deleteTungstenNetwork(DeleteTungstenNetworkCmd cmd) throws IOException; + ApiObjectBase getTungstenObjectByUUID(Class cls, String uuid) throws IOException; +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java new file mode 100644 index 000000000000..d0bdc377bacc --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java @@ -0,0 +1,299 @@ +package org.apache.cloudstack.network.tungsten.service; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.component.ManagerBase; +import com.google.common.collect.Lists; +import net.juniper.contrail.api.ApiConnector; +import net.juniper.contrail.api.ApiConnectorFactory; +import net.juniper.contrail.api.ApiObjectBase; +import net.juniper.contrail.api.types.InstanceIp; +import net.juniper.contrail.api.types.MacAddressesType; +import net.juniper.contrail.api.types.NetworkIpam; +import net.juniper.contrail.api.types.Project; +import net.juniper.contrail.api.types.SecurityGroup; +import net.juniper.contrail.api.types.SubnetType; +import net.juniper.contrail.api.types.VirtualMachine; +import net.juniper.contrail.api.types.VirtualMachineInterface; +import net.juniper.contrail.api.types.VirtualNetwork; +import net.juniper.contrail.api.types.VnSubnetsType; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.Configurable; +import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenInstanceIpCmd; +import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenNetworkCmd; +import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenVirtualMachineCmd; +import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenVmInterfaceCmd; +import org.apache.cloudstack.network.tungsten.api.command.DeleteTungstenNetworkCmd; +import org.apache.cloudstack.network.tungsten.api.command.ListTungstenNetworkCmd; +import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVirtualMachineCmd; +import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVmInterfaceCmd; +import org.apache.cloudstack.network.tungsten.api.response.TungstenNetworkResponse; +import org.apache.cloudstack.network.tungsten.api.response.TungstenVirtualMachineResponse; +import org.apache.cloudstack.network.tungsten.api.response.TungstenVmInterfaceResponse; +import org.apache.commons.io.IOUtils; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import javax.naming.ConfigurationException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; + +@Component +public class TungstenManagerImpl extends ManagerBase implements TungstenManager, Configurable { + + private static final Logger s_logger = Logger.getLogger(TungstenManager.class); + + private ApiConnector _api; + private final String configuration = "plugins/network-elements/tungsten/conf/tungsten.properties"; + + @PostConstruct + public void init() throws ConfigurationException { + File configFile = PropertiesUtil.findConfigFile(configuration); + FileInputStream fileStream = null; + try { + String hostname = null; + int port = 0; + if (configFile == null) { + throw new FileNotFoundException("Tungsten config file not found!"); + } else { + final Properties configProps = new Properties(); + fileStream = new FileInputStream(configFile); + configProps.load(fileStream); + + hostname = configProps.getProperty("tungsten.api.hostname"); + String portStr = configProps.getProperty("tungsten.api.port"); + if (portStr != null && portStr.length() > 0) { + port = Integer.parseInt(portStr); + } + } + _api = ApiConnectorFactory.build(hostname, port); + } catch (IOException ex) { + s_logger.warn("Unable to read " + configuration, ex); + throw new ConfigurationException(); + } catch (Exception ex) { + s_logger.debug("Exception in configure: " + ex); + ex.printStackTrace(); + throw new ConfigurationException(); + } finally { + IOUtils.closeQuietly(fileStream); + } + } + + @Override + public List> getCommands() { + return Lists.>newArrayList( + ListTungstenNetworkCmd.class, + CreateTungstenNetworkCmd.class, + DeleteTungstenNetworkCmd.class, + CreateTungstenVmInterfaceCmd.class, + CreateTungstenVirtualMachineCmd.class, + CreateTungstenInstanceIpCmd.class, + ListTungstenVirtualMachineCmd.class, + ListTungstenVmInterfaceCmd.class + ); + } + + @Override + public ListResponse getNetworks(ListTungstenNetworkCmd cmd) throws IOException{ + List networks; + ListResponse response = new ListResponse<>(); + List tungstenNetworkResponses = new ArrayList<>(); + + if(cmd.getNetworkUUID() != null) + networks = Arrays.asList((VirtualNetwork)_api.findById(VirtualNetwork.class, cmd.getNetworkUUID())); + else + networks = (List) _api.list(VirtualNetwork.class, null); + + if(networks != null && !networks.isEmpty()){ + for(VirtualNetwork virtualNetwork : networks){ + TungstenNetworkResponse tungstenNetworkResponse = TungstenResponseHelper.createTungstenNetworkResponse(virtualNetwork); + tungstenNetworkResponses.add(tungstenNetworkResponse); + } + } + response.setResponses(tungstenNetworkResponses); + return response; + } + + @Override + public ListResponse getVmInterfaces(ListTungstenVmInterfaceCmd cmd) throws IOException{ + List vmInterfaces; + ListResponse response = new ListResponse<>(); + List tungstenVmInterfaceResponses = new ArrayList<>(); + + if(cmd.getVmInterfaceUUID() != null) + vmInterfaces = Arrays.asList((VirtualMachineInterface)getTungstenObjectByUUID(VirtualMachineInterface.class, cmd.getVmInterfaceUUID())); + else + vmInterfaces = (List) _api.list(VirtualMachineInterface.class, null); + + if(vmInterfaces != null && !vmInterfaces.isEmpty()){ + for(VirtualMachineInterface vmInterface : vmInterfaces){ + TungstenVmInterfaceResponse tungstenVmInterfaceResponse = TungstenResponseHelper.createTungstenVmInterfaceResponse(vmInterface); + tungstenVmInterfaceResponses.add(tungstenVmInterfaceResponse); + } + } + response.setResponses(tungstenVmInterfaceResponses); + return response; + } + + public ListResponse getVirtualMachines(ListTungstenVirtualMachineCmd cmd) throws IOException{ + List virtualMachines; + ListResponse response = new ListResponse<>(); + List tungstenVirtualMachineResponses = new ArrayList<>(); + + if(cmd.getVirtualMachineUUID() != null) + virtualMachines = Arrays.asList((VirtualMachine)_api.findById(VirtualMachine.class, cmd.getVirtualMachineUUID())); + else + virtualMachines = (List) _api.list(VirtualMachine.class, null); + + if(virtualMachines != null && !virtualMachines.isEmpty()){ + for(VirtualMachine virtualMachine : virtualMachines){ + TungstenVirtualMachineResponse tungstenVirtualMachineResponse = TungstenResponseHelper.createTungstenVirtualMachineResponse(virtualMachine); + tungstenVirtualMachineResponses.add(tungstenVirtualMachineResponse); + } + } + response.setResponses(tungstenVirtualMachineResponses); + return response; + } + + @Override + public VirtualNetwork createTungstenNetwork(CreateTungstenNetworkCmd cmd){ + VirtualNetwork network = new VirtualNetwork(); + try { + network.setName(cmd.getName()); + network.setNetworkIpam(getNetworkIpam(cmd), getVnSubnetsType(cmd)); + _api.create(network); + return (VirtualNetwork) _api.findByFQN(VirtualNetwork.class, getFqnName(network)); + } catch (IOException e) { + s_logger.error("Unable to read " + configuration, e); + return null; + } + } + + @Override + public VirtualMachine createTungstenVirtualMachine(CreateTungstenVirtualMachineCmd cmd){ + VirtualMachine virtualMachine = new VirtualMachine(); + try { + virtualMachine.setName(cmd.getName()); + _api.create(virtualMachine); + return (VirtualMachine) _api.findByFQN(VirtualMachine.class, getFqnName(virtualMachine)); + } catch (IOException e) { + s_logger.error("Unable to read " + configuration, e); + return null; + } + } + + @Override + public InstanceIp createInstanceIp(CreateTungstenInstanceIpCmd cmd){ + InstanceIp instanceIp = new InstanceIp(); + try{ + instanceIp.setName(cmd.getName()); + VirtualMachineInterface virtualMachineInterface = (VirtualMachineInterface) getTungstenObjectByUUID(VirtualMachineInterface.class, cmd.getTungstenVmInterfaceUuid()); + VirtualNetwork virtualNetwork = (VirtualNetwork) getTungstenObjectByUUID(VirtualNetwork.class, cmd.getTungstenNetworkUuid()); + if(virtualNetwork != null) + instanceIp.setVirtualNetwork(virtualNetwork); + if(virtualMachineInterface != null) + instanceIp.setVirtualMachineInterface(virtualMachineInterface); + instanceIp.setAddress(cmd.getTungstenInstanceIpAddress()); + _api.create(instanceIp); + return (InstanceIp) _api.findByFQN(InstanceIp.class, getFqnName(instanceIp)); + } catch (IOException e) { + s_logger.error("Unable to read " + configuration, e); + return null; + } + } + + @Override + public VirtualMachineInterface createTungstenVirtualMachineInterface(CreateTungstenVmInterfaceCmd cmd){ + VirtualMachineInterface virtualMachineInterface = new VirtualMachineInterface(); + try { + virtualMachineInterface.setName(cmd.getName()); + Project project = (Project) getTungstenObjectByUUID(Project.class, cmd.getTungstenProjectUuid()); + VirtualNetwork virtualNetwork = (VirtualNetwork) getTungstenObjectByUUID(VirtualNetwork.class, cmd.getTungstenNetworkUuid()); + VirtualMachine virtualMachine = (VirtualMachine) getTungstenObjectByUUID(VirtualMachine.class, cmd.getTungstenVirtualMachineUuid()); + SecurityGroup securityGroup = (SecurityGroup) getTungstenObjectByUUID(SecurityGroup.class, cmd.getTungstenSecurityGroupUuid()); + if(virtualNetwork != null) + virtualMachineInterface.setVirtualNetwork(virtualNetwork); + if(virtualMachine != null) + virtualMachineInterface.setVirtualMachine(virtualMachine); + if(securityGroup != null) + virtualMachineInterface.setSecurityGroup(securityGroup); + if(project != null) + virtualMachineInterface.setParent(project); + if(cmd.getTungstenVmInterfaceMacAddresses() != null && !cmd.getTungstenVmInterfaceMacAddresses().isEmpty()) + virtualMachineInterface.setMacAddresses(new MacAddressesType(cmd.getTungstenVmInterfaceMacAddresses())); + _api.create(virtualMachineInterface); + return (VirtualMachineInterface) _api.findByFQN(VirtualMachineInterface.class, getFqnName(virtualMachineInterface)); + } catch (IOException e) { + s_logger.error("Unable to read " + configuration, e); + return null; + } + } + + @Override + public ApiObjectBase getTungstenObjectByUUID(Class cls, String uuid) throws IOException { + if(uuid != null) + return _api.findById(cls, uuid); + else + return null; + } + + public NetworkIpam getNetworkIpam(CreateTungstenNetworkCmd cmd) throws IOException { + if(cmd.getNetworkIpamUUID() != null){ + NetworkIpam networkIpam = (NetworkIpam) _api.findById(NetworkIpam.class, cmd.getNetworkIpamUUID()); + if(networkIpam != null) + return networkIpam; + } + NetworkIpam networkIpam = new NetworkIpam(); + networkIpam.setName(cmd.getName() + "-ipam"); + _api.create(networkIpam); + return (NetworkIpam) _api.findByFQN(NetworkIpam.class, getFqnName(networkIpam)); + } + + public VnSubnetsType getVnSubnetsType(CreateTungstenNetworkCmd cmd){ + List allocationPoolTypes = new ArrayList<>(); + allocationPoolTypes.add(new VnSubnetsType.IpamSubnetType.AllocationPoolType(cmd.getIpAllocPoolStart(), cmd.getIpAllocPoolEnd())); + VnSubnetsType.IpamSubnetType ipamSubnetType = new VnSubnetsType.IpamSubnetType( + new SubnetType(cmd.getSubnetIpPrefix(), cmd.getSubnetIpPrefixLength()), cmd.getDefaultGateway(), + null, cmd.isEnableDHCP(), cmd.getDnsNameservers(), allocationPoolTypes, cmd.isAddrFromStart(), null, null, null); + return new VnSubnetsType(Arrays.asList(ipamSubnetType), null); + } + + @Override + public VirtualNetwork deleteTungstenNetwork(DeleteTungstenNetworkCmd cmd) throws IOException { + VirtualNetwork network = (VirtualNetwork)_api.findById(VirtualNetwork.class, cmd.getUuid()); + if(network != null) { + _api.delete(network); + return network; + } + else + throw new InvalidParameterValueException("Unable to find tungsten network with UUID: " + cmd.getUuid()); + } + + @Override + public String getConfigComponentName() { + return TungstenManager.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[0]; + } + + public String getFqnName(ApiObjectBase obj){ + StringBuilder sb = new StringBuilder(); + for(String item : obj.getQualifiedName()){ + sb.append(item); + sb.append(":"); + } + sb.deleteCharAt(sb.toString().length()-1); + return sb.toString(); + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java new file mode 100644 index 000000000000..d880382ddee0 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java @@ -0,0 +1,67 @@ +package org.apache.cloudstack.network.tungsten.service; + +import net.juniper.contrail.api.ApiPropertyBase; +import net.juniper.contrail.api.ObjectReference; +import net.juniper.contrail.api.types.InstanceIp; +import net.juniper.contrail.api.types.VirtualMachine; +import net.juniper.contrail.api.types.VirtualMachineInterface; +import net.juniper.contrail.api.types.VirtualNetwork; +import org.apache.cloudstack.network.tungsten.api.response.TungstenInstanceIpResponse; +import org.apache.cloudstack.network.tungsten.api.response.TungstenNetworkResponse; +import org.apache.cloudstack.network.tungsten.api.response.TungstenVirtualMachineResponse; +import org.apache.cloudstack.network.tungsten.api.response.TungstenVmInterfaceResponse; + +public class TungstenResponseHelper { + + public static TungstenNetworkResponse createTungstenNetworkResponse(VirtualNetwork virtualNetwork){ + TungstenNetworkResponse tungstenNetworkResponse = new TungstenNetworkResponse(); + tungstenNetworkResponse.setName(virtualNetwork.getName()); + tungstenNetworkResponse.setParentUuid(virtualNetwork.getParentUuid()); + tungstenNetworkResponse.setUuid(virtualNetwork.getUuid()); + tungstenNetworkResponse.setFqName(virtualNetwork.getQualifiedName()); + tungstenNetworkResponse.setObjectName("tungstenVirtualNetwork"); + return tungstenNetworkResponse; + } + + public static TungstenVirtualMachineResponse createTungstenVirtualMachineResponse(VirtualMachine virtualMachine){ + TungstenVirtualMachineResponse tungstenVirtualMachineResponse = new TungstenVirtualMachineResponse(); + tungstenVirtualMachineResponse.setName(virtualMachine.getName()); + tungstenVirtualMachineResponse.setUuid(virtualMachine.getUuid()); + + if(virtualMachine.getVirtualMachineInterfaceBackRefs() != null){ + for(ObjectReference item : virtualMachine.getVirtualMachineInterfaceBackRefs()){ + tungstenVirtualMachineResponse.getVmInterfacesUuid().add(item.getUuid()); + } + } + + tungstenVirtualMachineResponse.setObjectName("tungstenVirtualMachine"); + return tungstenVirtualMachineResponse; + } + + public static TungstenVmInterfaceResponse createTungstenVmInterfaceResponse(VirtualMachineInterface virtualMachineInterface){ + TungstenVmInterfaceResponse tungstenVmInterfaceResponse = new TungstenVmInterfaceResponse(); + tungstenVmInterfaceResponse.setName(virtualMachineInterface.getName()); + tungstenVmInterfaceResponse.setUuid(virtualMachineInterface.getUuid()); + tungstenVmInterfaceResponse.setParentUuid(virtualMachineInterface.getParentUuid()); + + if(virtualMachineInterface.getVirtualNetwork() != null) { + for(ObjectReference item : virtualMachineInterface.getVirtualNetwork()){ + tungstenVmInterfaceResponse.getVirtualNetworksUuid().add(item.getUuid()); + } + } + + if(virtualMachineInterface.getVirtualMachine() != null){ + for(ObjectReference item : virtualMachineInterface.getVirtualMachine()){ + tungstenVmInterfaceResponse.getVirtualMachinesUuid().add(item.getUuid()); + } + } + tungstenVmInterfaceResponse.setObjectName("tungstenVirtualMachineInterface"); + return tungstenVmInterfaceResponse; + } + + public static TungstenInstanceIpResponse createTungstenInstanceIpResponse(InstanceIp instanceIp){ + TungstenInstanceIpResponse tungstenInstanceIpResponse = new TungstenInstanceIpResponse(); + tungstenInstanceIpResponse.setName(instanceIp.getName()); + return tungstenInstanceIpResponse; + } +} diff --git a/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/module.properties b/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/module.properties new file mode 100644 index 000000000000..72422a42b8ca --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/module.properties @@ -0,0 +1,21 @@ +# +# 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. +# + +name=tungsten +parent=network \ No newline at end of file diff --git a/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/spring-tungsten-context.xml b/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/spring-tungsten-context.xml new file mode 100644 index 000000000000..2ae530b44b39 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/spring-tungsten-context.xml @@ -0,0 +1,32 @@ + + + + + + diff --git a/plugins/pom.xml b/plugins/pom.xml index 8534000afc0f..f4792eddc6ee 100755 --- a/plugins/pom.xml +++ b/plugins/pom.xml @@ -106,6 +106,7 @@ network-elements/stratosphere-ssp network-elements/brocade-vcs network-elements/vxlan + network-elements/tungsten outofbandmanagement-drivers/ipmitool outofbandmanagement-drivers/nested-cloudstack diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index 441b21f1d920..6bad7cbe9050 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -87,6 +87,10 @@ 'OpenDaylight': 'Network', 'createServiceInstance': 'Network', 'addGloboDnsHost': 'Network', + 'createTungstenVmInterface' : 'Tungsten', + 'createTungstenInstanceIp' : 'Tungsten', + 'listTungstenVirtualMachines' : 'Tungsten', + 'listTungstenVmInterfaces' : 'Tungsten', 'Vpn': 'VPN', 'Limit': 'Limit', 'ResourceCount': 'Limit', From e8e687a789246e5f2125ce430b87cb94308d4997 Mon Sep 17 00:00:00 2001 From: rtodirica Date: Tue, 7 Jul 2020 10:42:04 +0300 Subject: [PATCH 02/62] Update the createNetwork endpoint params description --- .../tungsten/api/command/CreateTungstenNetworkCmd.java | 8 ++++---- .../tungsten/api/response/TungstenInstanceIpResponse.java | 2 +- .../network/tungsten/service/TungstenResponseHelper.java | 1 + 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenNetworkCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenNetworkCmd.java index 25e093725a87..32cae841e624 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenNetworkCmd.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenNetworkCmd.java @@ -56,13 +56,13 @@ public class CreateTungstenNetworkCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_SUBNET_IP_PREFIX_LEN, type = CommandType.INTEGER, description = "Subnet ip prefix length") private int subnetIpPrefixLength; - @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_DEFAULT_GATEWAY, type = CommandType.STRING, description = "Tungsten network default gateway") + @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_DEFAULT_GATEWAY, type = CommandType.STRING, description = "Default-gateway ip address in the subnet, if not provided one is auto generated by the system.") private String defaultGateway; - @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_ENABLE_DHC, type = CommandType.BOOLEAN, description = "Tungsten network enable dhcp") + @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_ENABLE_DHCP, type = CommandType.BOOLEAN, description = "Enable DHCP for the VM(s) in this subnet") private boolean enableDHCP; - @Parameter(name = ApiConstants.TUNGSTEN_DNS_NAME_SERVERS, type = CommandType.LIST, description = "Tungsten network DNS name servers") + @Parameter(name = ApiConstants.TUNGSTEN_DNS_NAME_SERVERS, type = CommandType.LIST, description = "Tenant DNS servers ip address in tenant DNS method") private List dnsNameservers; @Parameter(name = ApiConstants.TUNGSTEN_IP_ALLOC_POOL_START, type = CommandType.STRING, description = "Tungsten network ip allocation pool start") @@ -71,7 +71,7 @@ public class CreateTungstenNetworkCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.TUNGSTEN_IP_ALLOC_POOL_END, type = CommandType.STRING, description = "Tungsten network ip allocation pool end") private String ipAllocPoolEnd; - @Parameter(name = ApiConstants.TUNGSTEN_ADDR_FROM_START, type = CommandType.BOOLEAN, description = "Subnet ip prefix") + @Parameter(name = ApiConstants.TUNGSTEN_ADDR_FROM_START, type = CommandType.BOOLEAN, description = "Start address allocation from start or from end of address range.") private boolean addrFromStart; @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_SUBNET_NAME, type = CommandType.STRING, description = "Tungsten network subnet name") diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenInstanceIpResponse.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenInstanceIpResponse.java index ea8a9ccf5dbb..cf155289cd04 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenInstanceIpResponse.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenInstanceIpResponse.java @@ -8,7 +8,7 @@ public class TungstenInstanceIpResponse extends BaseResponse { @SerializedName(ApiConstants.NAME) - @Param(description = "name of the tungsten network") + @Param(description = "name of the tungsten instance ip") private String name; public String getName() { diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java index d880382ddee0..8f2ce3f24f0d 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java @@ -62,6 +62,7 @@ public static TungstenVmInterfaceResponse createTungstenVmInterfaceResponse(Virt public static TungstenInstanceIpResponse createTungstenInstanceIpResponse(InstanceIp instanceIp){ TungstenInstanceIpResponse tungstenInstanceIpResponse = new TungstenInstanceIpResponse(); tungstenInstanceIpResponse.setName(instanceIp.getName()); + tungstenInstanceIpResponse.setObjectName("tungstenInstanceIp"); return tungstenInstanceIpResponse; } } From 1be73ca25c4e58232f874f4ee2770d4c5637e3ed Mon Sep 17 00:00:00 2001 From: Huy Le Date: Wed, 8 Jul 2020 09:33:51 +0700 Subject: [PATCH 03/62] test commit --- plugins/network-elements/tungsten/conf/test.txt | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 plugins/network-elements/tungsten/conf/test.txt diff --git a/plugins/network-elements/tungsten/conf/test.txt b/plugins/network-elements/tungsten/conf/test.txt new file mode 100644 index 000000000000..e69de29bb2d1 From 64736de6060342a6ef9effbae5d380985d70d188 Mon Sep 17 00:00:00 2001 From: Huy Le Date: Mon, 27 Jul 2020 11:36:06 +0700 Subject: [PATCH 04/62] tungsten vrouter api & vrouter vif driver --- .../kvm/resource/VRouterVifDriver.java | 95 ++++++++++++ .../network-elements/tungsten/conf/test.txt | 0 .../tungsten/conf/tungsten.properties | 2 + .../network/tungsten/vrouter/Port.java | 139 ++++++++++++++++++ .../tungsten/vrouter/VRouterApiConnector.java | 13 ++ .../vrouter/VRouterApiConnectorFactory.java | 13 ++ .../vrouter/VRouterApiConnectorImpl.java | 97 ++++++++++++ .../vm/network/tungsten/create_tap_device.sh | 2 + .../vm/network/tungsten/delete_tap_device.sh | 1 + 9 files changed, 362 insertions(+) create mode 100644 plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/VRouterVifDriver.java delete mode 100644 plugins/network-elements/tungsten/conf/test.txt create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/Port.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnector.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnectorFactory.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnectorImpl.java create mode 100644 scripts/vm/network/tungsten/create_tap_device.sh create mode 100644 scripts/vm/network/tungsten/delete_tap_device.sh diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/VRouterVifDriver.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/VRouterVifDriver.java new file mode 100644 index 000000000000..1fb0fca20188 --- /dev/null +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/VRouterVifDriver.java @@ -0,0 +1,95 @@ +package com.cloud.hypervisor.kvm.resource; + +import com.cloud.agent.api.to.NicTO; +import com.cloud.exception.InternalErrorException; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.script.Script; +import org.apache.log4j.Logger; +import org.libvirt.LibvirtException; + +import java.util.Map; + +import javax.naming.ConfigurationException; + +public class VRouterVifDriver extends VifDriverBase { + private static final Logger s_logger = Logger.getLogger(VRouterVifDriver.class); + private int _timeout; + private String _createTapDeviceScript; + private String _deleteTapDeviceScript; + + @Override + public void configure(final Map params) throws ConfigurationException { + super.configure(params); + + String tungstenScriptsDir = (String) params.get("tungsten.scripts.dir"); + tungstenScriptsDir = + tungstenScriptsDir == null ? "scripts/vm/network/tungsten" : tungstenScriptsDir; + + final String value = (String) params.get("scripts.timeout"); + _timeout = NumbersUtil.parseInt(value, 30 * 60) * 1000; + + _createTapDeviceScript = Script.findScript(tungstenScriptsDir, "create_tap_device.sh"); + _deleteTapDeviceScript = Script.findScript(tungstenScriptsDir, "delete_tap_device.sh"); + + if (_createTapDeviceScript == null) { + throw new ConfigurationException("Unable to find create_tap_device.sh"); + } + + if (_deleteTapDeviceScript == null) { + throw new ConfigurationException("Unable to find delete_tap_device.sh"); + } + } + + @Override + public LibvirtVMDef.InterfaceDef plug(final NicTO nic, final String guestOsType, + final String nicAdapter, final Map extraConfig) + throws InternalErrorException, LibvirtException { + + final String tapDeviceName = getTapName(nic.getMac()); + final String script = _createTapDeviceScript; + + final Script command = new Script(script, _timeout, s_logger); + command.add("name", tapDeviceName); + + final String result = command.execute(); + if (result != null) { + throw new InternalErrorException( + "Failed to create tap device " + tapDeviceName + ": " + result); + } + + final LibvirtVMDef.InterfaceDef intf = new LibvirtVMDef.InterfaceDef(); + intf.defEthernet(tapDeviceName, nic.getMac(), getGuestNicModel(guestOsType, nicAdapter)); + + return intf; + } + + @Override + public void unplug(final LibvirtVMDef.InterfaceDef iface) { + final String tapDeviceName = getTapName(iface.getMacAddress()); + final String script = _createTapDeviceScript; + + final Script command = new Script(script, _timeout, s_logger); + command.add("name", tapDeviceName); + + final String result = command.execute(); + if (result != null) { + s_logger.error("Failed to delete tap device " + tapDeviceName + ": " + result); + } + } + + @Override + public void attach(final LibvirtVMDef.InterfaceDef iface) { + } + + @Override + public void detach(final LibvirtVMDef.InterfaceDef iface) { + } + + @Override + public void createControlNetwork(final String privBrName) { + } + + private String getTapName(final String macAddress) { + return "tap" + macAddress.replaceAll(":", ""); + } +} diff --git a/plugins/network-elements/tungsten/conf/test.txt b/plugins/network-elements/tungsten/conf/test.txt deleted file mode 100644 index e69de29bb2d1..000000000000 diff --git a/plugins/network-elements/tungsten/conf/tungsten.properties b/plugins/network-elements/tungsten/conf/tungsten.properties index 30a89c610eca..3665554280ec 100644 --- a/plugins/network-elements/tungsten/conf/tungsten.properties +++ b/plugins/network-elements/tungsten/conf/tungsten.properties @@ -17,3 +17,5 @@ tungsten.api.hostname=10.102.12.239 tungsten.api.port=8082 +tungsten.vrouter.hostname=localhost +tungsten.vrouter.port=9091 diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/Port.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/Port.java new file mode 100644 index 000000000000..af0bf3445297 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/Port.java @@ -0,0 +1,139 @@ +package org.apache.cloudstack.network.tungsten.vrouter; + +import com.google.gson.annotations.SerializedName; + +public class Port { + private static final String NONE = "None"; + + @SerializedName("id") + private String id = NONE; + + @SerializedName("instance-id") + private String instanceId = NONE; + + @SerializedName("display-name") + private String displayName = NONE; + + @SerializedName("vn-id") + private String vnId = NONE; + + @SerializedName("ip-address") + private String ipAddress = NONE; + + @SerializedName("mac-address") + private String macAddress = NONE; + + @SerializedName("vm-project-id") + private String vmProjectId = NONE; + + @SerializedName("rx-vlan-id") + private short rxVlanId = -1; + + @SerializedName("tx-vlan-id") + private short txVlanId = -1; + + @SerializedName("system-name") + private String tapInterfaceName = NONE; + + @SerializedName("type") + private int type = 0; + + @SerializedName("ip6-address") + private String ipv6Address = NONE; + + public String getId() { + return id; + } + + public void setId(final String id) { + this.id = id; + } + + public String getInstanceId() { + return instanceId; + } + + public void setInstanceId(final String instanceId) { + this.instanceId = instanceId; + } + + public String getDisplayName() { + return displayName; + } + + public void setDisplayName(final String displayName) { + this.displayName = displayName; + } + + public String getVnId() { + return vnId; + } + + public void setVnId(final String vnId) { + this.vnId = vnId; + } + + public String getIpAddress() { + return ipAddress; + } + + public void setIpAddress(final String ipAddress) { + this.ipAddress = ipAddress; + } + + public String getMacAddress() { + return macAddress; + } + + public void setMacAddress(final String macAddress) { + this.macAddress = macAddress; + } + + public String getVmProjectId() { + return vmProjectId; + } + + public void setVmProjectId(final String vmProjectId) { + this.vmProjectId = vmProjectId; + } + + public short getRxVlanId() { + return rxVlanId; + } + + public void setRxVlanId(final short rxVlanId) { + this.rxVlanId = rxVlanId; + } + + public short getTxVlanId() { + return txVlanId; + } + + public void setTxVlanId(final short txVlanId) { + this.txVlanId = txVlanId; + } + + public String getTapInterfaceName() { + return tapInterfaceName; + } + + public void setTapInterfaceName(final String tapInterfaceName) { + this.tapInterfaceName = tapInterfaceName; + } + + public int getType() { + return type; + } + + public void setType(final int type) { + this.type = type; + } + + public String getIpv6Address() { + return ipv6Address; + } + + public void setIpv6Address(final String ipv6Address) { + this.ipv6Address = ipv6Address; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnector.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnector.java new file mode 100644 index 000000000000..fc46a2f39f2e --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnector.java @@ -0,0 +1,13 @@ +package org.apache.cloudstack.network.tungsten.vrouter; + +import java.io.IOException; + +public interface VRouterApiConnector { + boolean addPort(Port port) throws IOException; + + boolean deletePort(String portId); + + boolean enablePort(String portId); + + boolean disablePort(String portId); +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnectorFactory.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnectorFactory.java new file mode 100644 index 000000000000..85ad993a70af --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnectorFactory.java @@ -0,0 +1,13 @@ +package org.apache.cloudstack.network.tungsten.vrouter; + +public class VRouterApiConnectorFactory { + private static VRouterApiConnector vrouterApiConnector; + + public static VRouterApiConnector getInstance(String host, String port) { + if (vrouterApiConnector == null) { + vrouterApiConnector = new VRouterApiConnectorImpl(host, port); + } + + return vrouterApiConnector; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnectorImpl.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnectorImpl.java new file mode 100644 index 000000000000..0931ee366efa --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/VRouterApiConnectorImpl.java @@ -0,0 +1,97 @@ +package org.apache.cloudstack.network.tungsten.vrouter; + +import com.google.gson.Gson; +import com.google.gson.JsonObject; +import com.google.gson.JsonParser; +import org.apache.http.client.methods.CloseableHttpResponse; +import org.apache.http.client.methods.HttpDelete; +import org.apache.http.client.methods.HttpPost; +import org.apache.http.client.methods.HttpPut; +import org.apache.http.entity.StringEntity; +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; +import org.apache.http.util.EntityUtils; +import org.apache.log4j.Logger; + +import java.io.IOException; + +public class VRouterApiConnectorImpl implements VRouterApiConnector { + private static final Logger s_logger = Logger.getLogger(VRouterApiConnector.class); + private String _url; + + public VRouterApiConnectorImpl(String host, String port) { + _url = "http://" + host + ":" + port + "/"; + } + + @Override + public boolean addPort(final Port port) throws IOException { + final StringBuffer url = new StringBuffer(); + url.append(_url).append("port"); + Gson gson = new Gson(); + final String jsonData = gson.toJson(port); + HttpPost httpPost = new HttpPost(url.toString()); + httpPost.setEntity(new StringEntity(jsonData)); + try (CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse httpResponse = httpClient.execute(httpPost)) { + return getResponse(httpResponse); + } catch (IOException ex) { + s_logger.error("Failed to add vrouter port : " + ex.getMessage()); + return false; + } + } + + @Override + public boolean deletePort(final String portId) { + final StringBuffer url = new StringBuffer(); + url.append(_url).append("port/").append(portId); + HttpDelete httpDelete = new HttpDelete(url.toString()); + try (CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse httpResponse = httpClient.execute(httpDelete)) { + return getResponse(httpResponse); + } catch (IOException ex) { + s_logger.error("Failed to delete vrouter port : " + ex.getMessage()); + return false; + } + } + + @Override + public boolean enablePort(final String portId) { + final StringBuffer url = new StringBuffer(); + url.append(_url).append("enable-port/").append(portId); + HttpPut httpPut = new HttpPut(url.toString()); + try (CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse httpResponse = httpClient.execute(httpPut)) { + return getResponse(httpResponse); + } catch (IOException ex) { + s_logger.error("Failed to enable vrouter port : " + ex.getMessage()); + return false; + } + } + + @Override + public boolean disablePort(final String portId) { + final StringBuffer url = new StringBuffer(); + url.append(_url).append("disable-port/").append(portId); + HttpPut httpPut = new HttpPut(url.toString()); + try (CloseableHttpClient httpClient = HttpClients.createDefault(); + CloseableHttpResponse httpResponse = httpClient.execute(httpPut)) { + return getResponse(httpResponse); + } catch (IOException ex) { + s_logger.error("Failed to disable vrouter port : " + ex.getMessage()); + return false; + } + } + + private boolean getResponse(final CloseableHttpResponse httpResponse) throws IOException { + JsonParser parser = new JsonParser(); + String result = EntityUtils.toString(httpResponse.getEntity()); + JsonObject jsonObject = parser.parse(result).getAsJsonObject(); + if (jsonObject.entrySet().size() == 0) { + return true; + } else { + String error = jsonObject.get("error").getAsString(); + s_logger.error(error); + return false; + } + } +} diff --git a/scripts/vm/network/tungsten/create_tap_device.sh b/scripts/vm/network/tungsten/create_tap_device.sh new file mode 100644 index 000000000000..46060d38c5d0 --- /dev/null +++ b/scripts/vm/network/tungsten/create_tap_device.sh @@ -0,0 +1,2 @@ +ip tuntap add dev $1 mode tap +ip link set $1 up \ No newline at end of file diff --git a/scripts/vm/network/tungsten/delete_tap_device.sh b/scripts/vm/network/tungsten/delete_tap_device.sh new file mode 100644 index 000000000000..a633429dd563 --- /dev/null +++ b/scripts/vm/network/tungsten/delete_tap_device.sh @@ -0,0 +1 @@ +ip tuntap del dev $1 mode tap \ No newline at end of file From 899b4b6972a665ef5a16aa03e0550097bf1e6d6c Mon Sep 17 00:00:00 2001 From: Huy Le Date: Mon, 3 Aug 2020 10:20:18 +0700 Subject: [PATCH 05/62] vrouter add & delete command --- .../main/java/com/cloud/event/EventTypes.java | 2 + .../api/command/AddVRouterPortCmd.java | 137 +++++ .../api/command/DeleteVRouterPortCmd.java | 92 ++++ .../tungsten/service/TungstenManager.java | 36 +- .../tungsten/service/TungstenManagerImpl.java | 521 ++++++++++-------- 5 files changed, 558 insertions(+), 230 deletions(-) create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/AddVRouterPortCmd.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteVRouterPortCmd.java diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java index 9df1fc47c1c5..f351ab575661 100644 --- a/api/src/main/java/com/cloud/event/EventTypes.java +++ b/api/src/main/java/com/cloud/event/EventTypes.java @@ -166,6 +166,8 @@ public class EventTypes { public static final String EVENT_TUNGSTEN_VIRTUAL_MACHINE_CREATE = "TUNGSTEN.VIRTUAL.MACHINE.CREATE"; public static final String EVENT_TUNGSTEN_NETWORK_CREATE = "TUNGSTEN.NETWORK.CREATE"; public static final String EVENT_TUNGSTEN_INSTANCE_IP = "TUNGSTEN.INSTANCE.IP"; + public static final String EVENT_TUNGSTEN_ADD_VROUTER_PORT = "TUNGSTEN.VROUTER.PORT.ADD"; + public static final String EVENT_TUNGSTEN_DEL_VROUTER_PORT = "TUNGSTEN.VROUTER.PORT.DEL"; //NIC Events public static final String EVENT_NIC_CREATE = "NIC.CREATE"; diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/AddVRouterPortCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/AddVRouterPortCmd.java new file mode 100644 index 000000000000..b4d41e7217f9 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/AddVRouterPortCmd.java @@ -0,0 +1,137 @@ +package org.apache.cloudstack.network.tungsten.api.command; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.ProjectResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.network.tungsten.service.TungstenManager; + +import java.io.IOException; + +import javax.inject.Inject; + +@APICommand(name = "addVRouterPort", description = "Add VRouter Port", responseObject = + SuccessResponse.class) +public class AddVRouterPortCmd extends BaseAsyncCmd { + + private static final String s_name = "addvrouterportcmd"; + + //Owner information + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "An optional " + + "account for the virtual machine. Must be used with domainId.") + private String accountName; + + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = + DomainResponse.class, description = + "An optional domainId for the virtual machine. If the " + + "account parameter is used, domainId must also be used.") + private Long domainId; + + @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = + ProjectResponse.class, description = "Project ID for the service instance") + private Long projectId; + + @Parameter(name = ApiConstants.TUNGSTEN_VM_INTERFACE_UUID, type = CommandType.STRING, + description = "Tungsten Virtual Machine Interface UUID") + private String tungstenVmInterfaceUuid; + + @Parameter(name = ApiConstants.TUNGSTEN_VIRTUAL_MACHINE_UUID, type = CommandType.STRING, + description = "Tungsten virtual machine UUID") + private String tungstenVirtualMachineUuid; + + @Parameter(name = ApiConstants.TUNGSTEN_VM_INTERFACE_MAC_ADDRESS, type = CommandType.STRING, + description = "Tungsten virtual machine interface mac address") + private String tungstenVmInterfaceMacAddress; + + @Parameter(name = ApiConstants.TUNGSTEN_INSTANCE_IP_ADDRESS, type = CommandType.STRING, + description = "Tungsten Instance IP Address") + private String tungstenInstanceIpAddress; + + @Parameter(name = ApiConstants.TUNGSTEN_VM_NAME, type = CommandType.STRING, description = + "Tungsten virtual machine name") + private String tungstenVmName; + + @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_UUID, type = CommandType.STRING, description = + "Tungsten network UUID") + private String tungstenVnUuid; + + public String getTungstenVirtualMachineUuid() { + return tungstenVirtualMachineUuid; + } + + public String getTungstenVmInterfaceMacAddress() { + return tungstenVmInterfaceMacAddress; + } + + public String getTungstenInstanceIpAddress() { + return tungstenInstanceIpAddress; + } + + public String getTungstenVmInterfaceUuid() { + return tungstenVmInterfaceUuid; + } + + public Long getProjectId() { + return projectId; + } + + public String getTungstenVmName() { + return tungstenVmName; + } + + public String getTungstenVnUuid() { + return tungstenVnUuid; + } + + @Inject + TungstenManager tungstenManager; + + @Override + public String getEventType() { + return EventTypes.EVENT_TUNGSTEN_ADD_VROUTER_PORT; + } + + @Override + public String getEventDescription() { + return "Add vrouter port"; + } + + @Override + public void execute() + throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, + ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try { + SuccessResponse response = tungstenManager.addVRouterPort(this); + this.setResponseObject(response); + } catch (IOException ex) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to add vrouter port."); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true); + if (accountId == null) { + return CallContext.current().getCallingAccount().getId(); + } + + return accountId; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteVRouterPortCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteVRouterPortCmd.java new file mode 100644 index 000000000000..f02d6c4ac463 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteVRouterPortCmd.java @@ -0,0 +1,92 @@ +package org.apache.cloudstack.network.tungsten.api.command; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.ProjectResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.network.tungsten.service.TungstenManager; + +import java.io.IOException; + +import javax.inject.Inject; + +@APICommand(name = "deleteVRouterPort", description = "Delete VRouter Port", responseObject = + SuccessResponse.class) +public class DeleteVRouterPortCmd extends BaseAsyncCmd { + private static final String s_name = "deletevrouterportcmd"; + + //Owner information + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "An optional " + + "account for the virtual machine. Must be used with domainId.") + private String accountName; + + @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = + DomainResponse.class, description = + "An optional domainId for the virtual machine. If the " + + "account parameter is used, domainId must also be used.") + private Long domainId; + + @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = + ProjectResponse.class, description = "Project ID for the service instance") + private Long projectId; + + @Parameter(name = ApiConstants.TUNGSTEN_VM_INTERFACE_UUID, type = CommandType.STRING, + description = "Tungsten Virtual Machine Interface UUID") + private String tungstenVmInterfaceUuid; + + public String getTungstenVmInterfaceUuid() { + return tungstenVmInterfaceUuid; + } + + @Inject + TungstenManager tungstenManager; + + @Override + public String getEventType() { + return EventTypes.EVENT_TUNGSTEN_DEL_VROUTER_PORT; + } + + @Override + public String getEventDescription() { + return "Delete vrouter port"; + } + + @Override + public void execute() + throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, + ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try { + SuccessResponse response = tungstenManager.deleteVRouterPort(this); + this.setResponseObject(response); + } catch (IOException ex) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete vrouter port."); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true); + if (accountId == null) { + return CallContext.current().getCallingAccount().getId(); + } + + return accountId; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java index 78c4e4662427..33695d97c5a8 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java @@ -7,11 +7,14 @@ import net.juniper.contrail.api.types.VirtualMachineInterface; import net.juniper.contrail.api.types.VirtualNetwork; import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.network.tungsten.api.command.AddVRouterPortCmd; import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenInstanceIpCmd; import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenNetworkCmd; import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenVirtualMachineCmd; import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenVmInterfaceCmd; import org.apache.cloudstack.network.tungsten.api.command.DeleteTungstenNetworkCmd; +import org.apache.cloudstack.network.tungsten.api.command.DeleteVRouterPortCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenNetworkCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVirtualMachineCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVmInterfaceCmd; @@ -22,13 +25,28 @@ import java.io.IOException; public interface TungstenManager extends PluggableService { - ListResponse getNetworks(ListTungstenNetworkCmd cmd) throws IOException; - ListResponse getVmInterfaces(ListTungstenVmInterfaceCmd cmd) throws IOException; - ListResponse getVirtualMachines(ListTungstenVirtualMachineCmd cmd) throws IOException; - VirtualNetwork createTungstenNetwork(CreateTungstenNetworkCmd cmd); - VirtualMachine createTungstenVirtualMachine(CreateTungstenVirtualMachineCmd cmd); - VirtualMachineInterface createTungstenVirtualMachineInterface(CreateTungstenVmInterfaceCmd cmd); - InstanceIp createInstanceIp(CreateTungstenInstanceIpCmd cmd); - VirtualNetwork deleteTungstenNetwork(DeleteTungstenNetworkCmd cmd) throws IOException; - ApiObjectBase getTungstenObjectByUUID(Class cls, String uuid) throws IOException; + ListResponse getNetworks(ListTungstenNetworkCmd cmd) throws IOException; + + ListResponse getVmInterfaces(ListTungstenVmInterfaceCmd cmd) + throws IOException; + + ListResponse getVirtualMachines(ListTungstenVirtualMachineCmd cmd) + throws IOException; + + VirtualNetwork createTungstenNetwork(CreateTungstenNetworkCmd cmd); + + VirtualMachine createTungstenVirtualMachine(CreateTungstenVirtualMachineCmd cmd); + + VirtualMachineInterface createTungstenVirtualMachineInterface(CreateTungstenVmInterfaceCmd cmd); + + InstanceIp createInstanceIp(CreateTungstenInstanceIpCmd cmd); + + VirtualNetwork deleteTungstenNetwork(DeleteTungstenNetworkCmd cmd) throws IOException; + + ApiObjectBase getTungstenObjectByUUID(Class cls, String uuid) + throws IOException; + + SuccessResponse addVRouterPort(AddVRouterPortCmd cmd) throws IOException; + + SuccessResponse deleteVRouterPort(DeleteVRouterPortCmd cmd) throws IOException; } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java index d0bdc377bacc..98bfb4722904 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java @@ -18,25 +18,29 @@ import net.juniper.contrail.api.types.VirtualNetwork; import net.juniper.contrail.api.types.VnSubnetsType; import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.cloudstack.framework.config.ConfigKey; import org.apache.cloudstack.framework.config.Configurable; +import org.apache.cloudstack.network.tungsten.api.command.AddVRouterPortCmd; import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenInstanceIpCmd; import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenNetworkCmd; import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenVirtualMachineCmd; import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenVmInterfaceCmd; import org.apache.cloudstack.network.tungsten.api.command.DeleteTungstenNetworkCmd; +import org.apache.cloudstack.network.tungsten.api.command.DeleteVRouterPortCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenNetworkCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVirtualMachineCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVmInterfaceCmd; import org.apache.cloudstack.network.tungsten.api.response.TungstenNetworkResponse; import org.apache.cloudstack.network.tungsten.api.response.TungstenVirtualMachineResponse; import org.apache.cloudstack.network.tungsten.api.response.TungstenVmInterfaceResponse; +import org.apache.cloudstack.network.tungsten.vrouter.Port; +import org.apache.cloudstack.network.tungsten.vrouter.VRouterApiConnector; +import org.apache.cloudstack.network.tungsten.vrouter.VRouterApiConnectorFactory; import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; -import javax.naming.ConfigurationException; import java.io.File; import java.io.FileInputStream; import java.io.FileNotFoundException; @@ -46,254 +50,329 @@ import java.util.List; import java.util.Properties; +import javax.annotation.PostConstruct; +import javax.naming.ConfigurationException; + @Component public class TungstenManagerImpl extends ManagerBase implements TungstenManager, Configurable { - private static final Logger s_logger = Logger.getLogger(TungstenManager.class); - - private ApiConnector _api; - private final String configuration = "plugins/network-elements/tungsten/conf/tungsten.properties"; - - @PostConstruct - public void init() throws ConfigurationException { - File configFile = PropertiesUtil.findConfigFile(configuration); - FileInputStream fileStream = null; - try { - String hostname = null; - int port = 0; - if (configFile == null) { - throw new FileNotFoundException("Tungsten config file not found!"); - } else { - final Properties configProps = new Properties(); - fileStream = new FileInputStream(configFile); - configProps.load(fileStream); - - hostname = configProps.getProperty("tungsten.api.hostname"); - String portStr = configProps.getProperty("tungsten.api.port"); - if (portStr != null && portStr.length() > 0) { - port = Integer.parseInt(portStr); - } - } - _api = ApiConnectorFactory.build(hostname, port); - } catch (IOException ex) { - s_logger.warn("Unable to read " + configuration, ex); - throw new ConfigurationException(); - } catch (Exception ex) { - s_logger.debug("Exception in configure: " + ex); - ex.printStackTrace(); - throw new ConfigurationException(); - } finally { - IOUtils.closeQuietly(fileStream); - } - } + private static final Logger s_logger = Logger.getLogger(TungstenManager.class); - @Override - public List> getCommands() { - return Lists.>newArrayList( - ListTungstenNetworkCmd.class, - CreateTungstenNetworkCmd.class, - DeleteTungstenNetworkCmd.class, - CreateTungstenVmInterfaceCmd.class, - CreateTungstenVirtualMachineCmd.class, - CreateTungstenInstanceIpCmd.class, - ListTungstenVirtualMachineCmd.class, - ListTungstenVmInterfaceCmd.class - ); - } + private ApiConnector _api; + private VRouterApiConnector _vrouterApi; + private final String configuration = "plugins/network-elements/tungsten/conf/tungsten.properties"; - @Override - public ListResponse getNetworks(ListTungstenNetworkCmd cmd) throws IOException{ - List networks; - ListResponse response = new ListResponse<>(); - List tungstenNetworkResponses = new ArrayList<>(); - - if(cmd.getNetworkUUID() != null) - networks = Arrays.asList((VirtualNetwork)_api.findById(VirtualNetwork.class, cmd.getNetworkUUID())); - else - networks = (List) _api.list(VirtualNetwork.class, null); - - if(networks != null && !networks.isEmpty()){ - for(VirtualNetwork virtualNetwork : networks){ - TungstenNetworkResponse tungstenNetworkResponse = TungstenResponseHelper.createTungstenNetworkResponse(virtualNetwork); - tungstenNetworkResponses.add(tungstenNetworkResponse); - } - } - response.setResponses(tungstenNetworkResponses); - return response; - } + @PostConstruct + public void init() throws ConfigurationException { + File configFile = PropertiesUtil.findConfigFile(configuration); + FileInputStream fileStream = null; + try { + String hostname = null; + int port = 0; + String vrouterHost = null; + String vrouterPort = null; + if (configFile == null) { + throw new FileNotFoundException("Tungsten config file not found!"); + } else { + final Properties configProps = new Properties(); + fileStream = new FileInputStream(configFile); + configProps.load(fileStream); - @Override - public ListResponse getVmInterfaces(ListTungstenVmInterfaceCmd cmd) throws IOException{ - List vmInterfaces; - ListResponse response = new ListResponse<>(); - List tungstenVmInterfaceResponses = new ArrayList<>(); - - if(cmd.getVmInterfaceUUID() != null) - vmInterfaces = Arrays.asList((VirtualMachineInterface)getTungstenObjectByUUID(VirtualMachineInterface.class, cmd.getVmInterfaceUUID())); - else - vmInterfaces = (List) _api.list(VirtualMachineInterface.class, null); - - if(vmInterfaces != null && !vmInterfaces.isEmpty()){ - for(VirtualMachineInterface vmInterface : vmInterfaces){ - TungstenVmInterfaceResponse tungstenVmInterfaceResponse = TungstenResponseHelper.createTungstenVmInterfaceResponse(vmInterface); - tungstenVmInterfaceResponses.add(tungstenVmInterfaceResponse); - } - } - response.setResponses(tungstenVmInterfaceResponses); - return response; - } + hostname = configProps.getProperty("tungsten.api.hostname"); + String portStr = configProps.getProperty("tungsten.api.port"); - public ListResponse getVirtualMachines(ListTungstenVirtualMachineCmd cmd) throws IOException{ - List virtualMachines; - ListResponse response = new ListResponse<>(); - List tungstenVirtualMachineResponses = new ArrayList<>(); - - if(cmd.getVirtualMachineUUID() != null) - virtualMachines = Arrays.asList((VirtualMachine)_api.findById(VirtualMachine.class, cmd.getVirtualMachineUUID())); - else - virtualMachines = (List) _api.list(VirtualMachine.class, null); - - if(virtualMachines != null && !virtualMachines.isEmpty()){ - for(VirtualMachine virtualMachine : virtualMachines){ - TungstenVirtualMachineResponse tungstenVirtualMachineResponse = TungstenResponseHelper.createTungstenVirtualMachineResponse(virtualMachine); - tungstenVirtualMachineResponses.add(tungstenVirtualMachineResponse); - } + if (portStr != null && portStr.length() > 0) { + port = Integer.parseInt(portStr); } - response.setResponses(tungstenVirtualMachineResponses); - return response; + + vrouterHost = configProps.getProperty("tungsten.vrouter.hostname"); + vrouterPort = configProps.getProperty("tungsten.vrouter.port"); + } + _api = ApiConnectorFactory.build(hostname, port); + _vrouterApi = VRouterApiConnectorFactory.getInstance(vrouterHost, vrouterPort); + } catch (IOException ex) { + s_logger.warn("Unable to read " + configuration, ex); + throw new ConfigurationException(); + } catch (Exception ex) { + s_logger.debug("Exception in configure: " + ex); + ex.printStackTrace(); + throw new ConfigurationException(); + } finally { + IOUtils.closeQuietly(fileStream); } + } - @Override - public VirtualNetwork createTungstenNetwork(CreateTungstenNetworkCmd cmd){ - VirtualNetwork network = new VirtualNetwork(); - try { - network.setName(cmd.getName()); - network.setNetworkIpam(getNetworkIpam(cmd), getVnSubnetsType(cmd)); - _api.create(network); - return (VirtualNetwork) _api.findByFQN(VirtualNetwork.class, getFqnName(network)); - } catch (IOException e) { - s_logger.error("Unable to read " + configuration, e); - return null; - } + @Override + public List> getCommands() { + return Lists.>newArrayList(ListTungstenNetworkCmd.class, + CreateTungstenNetworkCmd.class, DeleteTungstenNetworkCmd.class, + CreateTungstenVmInterfaceCmd.class, CreateTungstenVirtualMachineCmd.class, + CreateTungstenInstanceIpCmd.class, ListTungstenVirtualMachineCmd.class, + ListTungstenVmInterfaceCmd.class, AddVRouterPortCmd.class, DeleteVRouterPortCmd.class); + } + + @Override + public ListResponse getNetworks(ListTungstenNetworkCmd cmd) + throws IOException { + List networks; + ListResponse response = new ListResponse<>(); + List tungstenNetworkResponses = new ArrayList<>(); + + if (cmd.getNetworkUUID() != null) + networks = Arrays.asList( + (VirtualNetwork) _api.findById(VirtualNetwork.class, cmd.getNetworkUUID())); + else + networks = (List) _api.list(VirtualNetwork.class, null); + + if (networks != null && !networks.isEmpty()) { + for (VirtualNetwork virtualNetwork : networks) { + TungstenNetworkResponse tungstenNetworkResponse = + TungstenResponseHelper.createTungstenNetworkResponse( + virtualNetwork); + tungstenNetworkResponses.add(tungstenNetworkResponse); + } } + response.setResponses(tungstenNetworkResponses); + return response; + } - @Override - public VirtualMachine createTungstenVirtualMachine(CreateTungstenVirtualMachineCmd cmd){ - VirtualMachine virtualMachine = new VirtualMachine(); - try { - virtualMachine.setName(cmd.getName()); - _api.create(virtualMachine); - return (VirtualMachine) _api.findByFQN(VirtualMachine.class, getFqnName(virtualMachine)); - } catch (IOException e) { - s_logger.error("Unable to read " + configuration, e); - return null; - } + @Override + public ListResponse getVmInterfaces(ListTungstenVmInterfaceCmd cmd) + throws IOException { + List vmInterfaces; + ListResponse response = new ListResponse<>(); + List tungstenVmInterfaceResponses = new ArrayList<>(); + + if (cmd.getVmInterfaceUUID() != null) + vmInterfaces = Arrays.asList( + (VirtualMachineInterface) getTungstenObjectByUUID(VirtualMachineInterface.class, + cmd.getVmInterfaceUUID())); + else + vmInterfaces = (List) _api.list(VirtualMachineInterface.class, null); + + if (vmInterfaces != null && !vmInterfaces.isEmpty()) { + for (VirtualMachineInterface vmInterface : vmInterfaces) { + TungstenVmInterfaceResponse tungstenVmInterfaceResponse = + TungstenResponseHelper.createTungstenVmInterfaceResponse( + vmInterface); + tungstenVmInterfaceResponses.add(tungstenVmInterfaceResponse); + } } + response.setResponses(tungstenVmInterfaceResponses); + return response; + } - @Override - public InstanceIp createInstanceIp(CreateTungstenInstanceIpCmd cmd){ - InstanceIp instanceIp = new InstanceIp(); - try{ - instanceIp.setName(cmd.getName()); - VirtualMachineInterface virtualMachineInterface = (VirtualMachineInterface) getTungstenObjectByUUID(VirtualMachineInterface.class, cmd.getTungstenVmInterfaceUuid()); - VirtualNetwork virtualNetwork = (VirtualNetwork) getTungstenObjectByUUID(VirtualNetwork.class, cmd.getTungstenNetworkUuid()); - if(virtualNetwork != null) - instanceIp.setVirtualNetwork(virtualNetwork); - if(virtualMachineInterface != null) - instanceIp.setVirtualMachineInterface(virtualMachineInterface); - instanceIp.setAddress(cmd.getTungstenInstanceIpAddress()); - _api.create(instanceIp); - return (InstanceIp) _api.findByFQN(InstanceIp.class, getFqnName(instanceIp)); - } catch (IOException e) { - s_logger.error("Unable to read " + configuration, e); - return null; - } + public ListResponse getVirtualMachines( + ListTungstenVirtualMachineCmd cmd) throws IOException { + List virtualMachines; + ListResponse response = new ListResponse<>(); + List tungstenVirtualMachineResponses = new ArrayList<>(); + + if (cmd.getVirtualMachineUUID() != null) + virtualMachines = Arrays.asList( + (VirtualMachine) _api.findById(VirtualMachine.class, cmd.getVirtualMachineUUID())); + else + virtualMachines = (List) _api.list(VirtualMachine.class, null); + + if (virtualMachines != null && !virtualMachines.isEmpty()) { + for (VirtualMachine virtualMachine : virtualMachines) { + TungstenVirtualMachineResponse tungstenVirtualMachineResponse = + TungstenResponseHelper.createTungstenVirtualMachineResponse( + virtualMachine); + tungstenVirtualMachineResponses.add(tungstenVirtualMachineResponse); + } } + response.setResponses(tungstenVirtualMachineResponses); + return response; + } - @Override - public VirtualMachineInterface createTungstenVirtualMachineInterface(CreateTungstenVmInterfaceCmd cmd){ - VirtualMachineInterface virtualMachineInterface = new VirtualMachineInterface(); - try { - virtualMachineInterface.setName(cmd.getName()); - Project project = (Project) getTungstenObjectByUUID(Project.class, cmd.getTungstenProjectUuid()); - VirtualNetwork virtualNetwork = (VirtualNetwork) getTungstenObjectByUUID(VirtualNetwork.class, cmd.getTungstenNetworkUuid()); - VirtualMachine virtualMachine = (VirtualMachine) getTungstenObjectByUUID(VirtualMachine.class, cmd.getTungstenVirtualMachineUuid()); - SecurityGroup securityGroup = (SecurityGroup) getTungstenObjectByUUID(SecurityGroup.class, cmd.getTungstenSecurityGroupUuid()); - if(virtualNetwork != null) - virtualMachineInterface.setVirtualNetwork(virtualNetwork); - if(virtualMachine != null) - virtualMachineInterface.setVirtualMachine(virtualMachine); - if(securityGroup != null) - virtualMachineInterface.setSecurityGroup(securityGroup); - if(project != null) - virtualMachineInterface.setParent(project); - if(cmd.getTungstenVmInterfaceMacAddresses() != null && !cmd.getTungstenVmInterfaceMacAddresses().isEmpty()) - virtualMachineInterface.setMacAddresses(new MacAddressesType(cmd.getTungstenVmInterfaceMacAddresses())); - _api.create(virtualMachineInterface); - return (VirtualMachineInterface) _api.findByFQN(VirtualMachineInterface.class, getFqnName(virtualMachineInterface)); - } catch (IOException e) { - s_logger.error("Unable to read " + configuration, e); - return null; - } + @Override + public VirtualNetwork createTungstenNetwork(CreateTungstenNetworkCmd cmd) { + VirtualNetwork network = new VirtualNetwork(); + try { + network.setName(cmd.getName()); + network.setNetworkIpam(getNetworkIpam(cmd), getVnSubnetsType(cmd)); + _api.create(network); + return (VirtualNetwork) _api.findByFQN(VirtualNetwork.class, getFqnName(network)); + } catch (IOException e) { + s_logger.error("Unable to read " + configuration, e); + return null; } + } - @Override - public ApiObjectBase getTungstenObjectByUUID(Class cls, String uuid) throws IOException { - if(uuid != null) - return _api.findById(cls, uuid); - else - return null; + @Override + public VirtualMachine createTungstenVirtualMachine(CreateTungstenVirtualMachineCmd cmd) { + VirtualMachine virtualMachine = new VirtualMachine(); + try { + virtualMachine.setName(cmd.getName()); + _api.create(virtualMachine); + return (VirtualMachine) _api.findByFQN(VirtualMachine.class, getFqnName(virtualMachine)); + } catch (IOException e) { + s_logger.error("Unable to read " + configuration, e); + return null; } + } - public NetworkIpam getNetworkIpam(CreateTungstenNetworkCmd cmd) throws IOException { - if(cmd.getNetworkIpamUUID() != null){ - NetworkIpam networkIpam = (NetworkIpam) _api.findById(NetworkIpam.class, cmd.getNetworkIpamUUID()); - if(networkIpam != null) - return networkIpam; - } - NetworkIpam networkIpam = new NetworkIpam(); - networkIpam.setName(cmd.getName() + "-ipam"); - _api.create(networkIpam); - return (NetworkIpam) _api.findByFQN(NetworkIpam.class, getFqnName(networkIpam)); + @Override + public InstanceIp createInstanceIp(CreateTungstenInstanceIpCmd cmd) { + InstanceIp instanceIp = new InstanceIp(); + try { + instanceIp.setName(cmd.getName()); + VirtualMachineInterface virtualMachineInterface = + (VirtualMachineInterface) getTungstenObjectByUUID( + VirtualMachineInterface.class, cmd.getTungstenVmInterfaceUuid()); + VirtualNetwork virtualNetwork = (VirtualNetwork) getTungstenObjectByUUID(VirtualNetwork.class, + cmd.getTungstenNetworkUuid()); + if (virtualNetwork != null) + instanceIp.setVirtualNetwork(virtualNetwork); + if (virtualMachineInterface != null) + instanceIp.setVirtualMachineInterface(virtualMachineInterface); + instanceIp.setAddress(cmd.getTungstenInstanceIpAddress()); + _api.create(instanceIp); + return (InstanceIp) _api.findByFQN(InstanceIp.class, getFqnName(instanceIp)); + } catch (IOException e) { + s_logger.error("Unable to read " + configuration, e); + return null; } + } - public VnSubnetsType getVnSubnetsType(CreateTungstenNetworkCmd cmd){ - List allocationPoolTypes = new ArrayList<>(); - allocationPoolTypes.add(new VnSubnetsType.IpamSubnetType.AllocationPoolType(cmd.getIpAllocPoolStart(), cmd.getIpAllocPoolEnd())); - VnSubnetsType.IpamSubnetType ipamSubnetType = new VnSubnetsType.IpamSubnetType( - new SubnetType(cmd.getSubnetIpPrefix(), cmd.getSubnetIpPrefixLength()), cmd.getDefaultGateway(), - null, cmd.isEnableDHCP(), cmd.getDnsNameservers(), allocationPoolTypes, cmd.isAddrFromStart(), null, null, null); - return new VnSubnetsType(Arrays.asList(ipamSubnetType), null); + @Override + public VirtualMachineInterface createTungstenVirtualMachineInterface( + CreateTungstenVmInterfaceCmd cmd) { + VirtualMachineInterface virtualMachineInterface = new VirtualMachineInterface(); + try { + virtualMachineInterface.setName(cmd.getName()); + Project project = (Project) getTungstenObjectByUUID(Project.class, + cmd.getTungstenProjectUuid()); + VirtualNetwork virtualNetwork = (VirtualNetwork) getTungstenObjectByUUID(VirtualNetwork.class, + cmd.getTungstenNetworkUuid()); + VirtualMachine virtualMachine = (VirtualMachine) getTungstenObjectByUUID(VirtualMachine.class, + cmd.getTungstenVirtualMachineUuid()); + SecurityGroup securityGroup = (SecurityGroup) getTungstenObjectByUUID(SecurityGroup.class, + cmd.getTungstenSecurityGroupUuid()); + if (virtualNetwork != null) + virtualMachineInterface.setVirtualNetwork(virtualNetwork); + if (virtualMachine != null) + virtualMachineInterface.setVirtualMachine(virtualMachine); + if (securityGroup != null) + virtualMachineInterface.setSecurityGroup(securityGroup); + if (project != null) + virtualMachineInterface.setParent(project); + if (cmd.getTungstenVmInterfaceMacAddresses() != null + && !cmd.getTungstenVmInterfaceMacAddresses().isEmpty()) + virtualMachineInterface.setMacAddresses( + new MacAddressesType(cmd.getTungstenVmInterfaceMacAddresses())); + _api.create(virtualMachineInterface); + return (VirtualMachineInterface) _api.findByFQN(VirtualMachineInterface.class, + getFqnName(virtualMachineInterface)); + } catch (IOException e) { + s_logger.error("Unable to read " + configuration, e); + return null; } + } - @Override - public VirtualNetwork deleteTungstenNetwork(DeleteTungstenNetworkCmd cmd) throws IOException { - VirtualNetwork network = (VirtualNetwork)_api.findById(VirtualNetwork.class, cmd.getUuid()); - if(network != null) { - _api.delete(network); - return network; - } - else - throw new InvalidParameterValueException("Unable to find tungsten network with UUID: " + cmd.getUuid()); + @Override + public ApiObjectBase getTungstenObjectByUUID(Class cls, String uuid) + throws IOException { + if (uuid != null) + return _api.findById(cls, uuid); + else + return null; + } + + public NetworkIpam getNetworkIpam(CreateTungstenNetworkCmd cmd) throws IOException { + if (cmd.getNetworkIpamUUID() != null) { + NetworkIpam networkIpam = (NetworkIpam) _api.findById(NetworkIpam.class, + cmd.getNetworkIpamUUID()); + if (networkIpam != null) + return networkIpam; } + NetworkIpam networkIpam = new NetworkIpam(); + networkIpam.setName(cmd.getName() + "-ipam"); + _api.create(networkIpam); + return (NetworkIpam) _api.findByFQN(NetworkIpam.class, getFqnName(networkIpam)); + } + + public VnSubnetsType getVnSubnetsType(CreateTungstenNetworkCmd cmd) { + List allocationPoolTypes = new ArrayList<>(); + allocationPoolTypes.add( + new VnSubnetsType.IpamSubnetType.AllocationPoolType(cmd.getIpAllocPoolStart(), + cmd.getIpAllocPoolEnd())); + VnSubnetsType.IpamSubnetType ipamSubnetType = new VnSubnetsType.IpamSubnetType( + new SubnetType(cmd.getSubnetIpPrefix(), cmd.getSubnetIpPrefixLength()), + cmd.getDefaultGateway(), null, cmd.isEnableDHCP(), cmd.getDnsNameservers(), + allocationPoolTypes, cmd.isAddrFromStart(), null, null, null); + return new VnSubnetsType(Arrays.asList(ipamSubnetType), null); + } + + @Override + public VirtualNetwork deleteTungstenNetwork(DeleteTungstenNetworkCmd cmd) throws IOException { + VirtualNetwork network = (VirtualNetwork) _api.findById(VirtualNetwork.class, cmd.getUuid()); + if (network != null) { + _api.delete(network); + return network; + } else + throw new InvalidParameterValueException( + "Unable to find tungsten network with UUID: " + cmd.getUuid()); + } - @Override - public String getConfigComponentName() { - return TungstenManager.class.getSimpleName(); + @Override + public SuccessResponse addVRouterPort(final AddVRouterPortCmd cmd) throws IOException { + Port port = new Port(); + port.setId(cmd.getTungstenVmInterfaceUuid()); + port.setInstanceId(cmd.getTungstenVirtualMachineUuid()); + port.setIpAddress(cmd.getTungstenInstanceIpAddress()); + port.setMacAddress(cmd.getTungstenVmInterfaceMacAddress()); + port.setTapInterfaceName(getTapName(cmd.getTungstenVmInterfaceMacAddress())); + port.setVmProjectId(String.valueOf(cmd.getProjectId())); + port.setDisplayName(cmd.getTungstenVmName()); + port.setVnId(cmd.getTungstenVnUuid()); + SuccessResponse successResponse = new SuccessResponse(cmd.getCommandName()); + if (_vrouterApi.addPort(port)) { + successResponse.setSuccess(true); + successResponse.setDisplayText("Success to add vrouter port"); + } else { + successResponse.setSuccess(false); + successResponse.setDisplayText("Fail to add vrouter port"); } + return successResponse; + } - @Override - public ConfigKey[] getConfigKeys() { - return new ConfigKey[0]; + @Override + public SuccessResponse deleteVRouterPort(final DeleteVRouterPortCmd cmd) throws IOException { + String portId = cmd.getTungstenVmInterfaceUuid(); + SuccessResponse successResponse = new SuccessResponse(cmd.getCommandName()); + if (_vrouterApi.deletePort(portId)) { + successResponse.setSuccess(true); + successResponse.setDisplayText("Success to delete vrouter port"); + } else { + successResponse.setSuccess(false); + successResponse.setDisplayText("Fail to delete vrouter port"); } + return successResponse; + } - public String getFqnName(ApiObjectBase obj){ - StringBuilder sb = new StringBuilder(); - for(String item : obj.getQualifiedName()){ - sb.append(item); - sb.append(":"); - } - sb.deleteCharAt(sb.toString().length()-1); - return sb.toString(); + @Override + public String getConfigComponentName() { + return TungstenManager.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[0]; + } + + public String getFqnName(ApiObjectBase obj) { + StringBuilder sb = new StringBuilder(); + for (String item : obj.getQualifiedName()) { + sb.append(item); + sb.append(":"); } + sb.deleteCharAt(sb.toString().length() - 1); + return sb.toString(); + } + + private String getTapName(final String macAddress) { + return "tap" + macAddress.replace(":", ""); + } } From 8633eac6434485e26d6e7628ead71cac0ca20375 Mon Sep 17 00:00:00 2001 From: rtodirica Date: Sun, 16 Aug 2020 18:54:57 +0300 Subject: [PATCH 06/62] Added tungsten provider Added network offering for tungsten Creating virtual network in tungsten when we create a network with tungsten offering Creating virtual machine and virtual machine interface in tungsten when we create a vm with a tungsten network --- .../main/java/com/cloud/network/Network.java | 6 + .../network/guru/NetworkGuruTungsten.java | 12 + .../com/cloud/offering/NetworkOffering.java | 2 + .../network/CreateNetworkOfferingCmd.java | 9 + .../user/network/CreateNetworkCmd.java | 110 +- .../api/response/NetworkOfferingResponse.java | 8 + .../api/response/NetworkResponse.java | 154 +- .../configuration/ConfigurationManager.java | 16 +- .../orchestration/NetworkOrchestrator.java | 944 +- .../java/com/cloud/network/dao/NetworkVO.java | 169 +- .../cloud/offerings/NetworkOfferingVO.java | 86 +- .../META-INF/db/schema-41400to41500.sql | 613 +- .../src/main/resources/components-example.xml | 14 +- .../management/ContrailManagerImpl.java | 39 +- .../network/guru/SspGuestNetworkGuru.java | 6 +- .../api/command/CreateTungstenNetworkCmd.java | 7 + .../CreateTungstenVirtualMachineCmd.java | 7 + .../api/command/DeleteTungstenNetworkCmd.java | 8 +- .../command/ListTungstenVirtualRouterCmd.java | 55 + .../TungstenVirtualRouterResponse.java | 32 + .../tungsten/service/TungstenElement.java | 133 + .../service/TungstenGuestNetworkGuru.java | 181 + .../tungsten/service/TungstenManager.java | 10 +- .../tungsten/service/TungstenManagerImpl.java | 295 +- .../service/TungstenResponseHelper.java | 10 + .../tungsten/service/TungstenService.java | 36 + .../tungsten/service/TungstenServiceImpl.java | 237 + .../tungsten/spring-tungsten-context.xml | 13 +- .../java/com/cloud/api/ApiResponseHelper.java | 29 +- .../api/query/vo/NetworkOfferingJoinVO.java | 8 + .../ConfigurationManagerImpl.java | 1858 +- .../guru/ExternalGuestNetworkGuru.java | 69 +- .../vpc/MockConfigurationManagerImpl.java | 75 +- .../CreateNetworkOfferingTest.java | 42 +- tools/apidoc/gen_toc.py | 1 + ui/l10n/en.js | 2492 ++ ui/scripts/configuration.js | 5965 ++++ ui/scripts/docs.js | 1417 + ui/scripts/network.js | 7174 +++++ ui/scripts/system.js | 23278 ++++++++++++++++ 40 files changed, 42211 insertions(+), 3409 deletions(-) create mode 100644 api/src/main/java/com/cloud/network/guru/NetworkGuruTungsten.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenVirtualRouterCmd.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenVirtualRouterResponse.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenService.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImpl.java mode change 100755 => 100644 server/src/main/java/com/cloud/configuration/ConfigurationManagerImpl.java create mode 100644 ui/l10n/en.js create mode 100644 ui/scripts/configuration.js create mode 100755 ui/scripts/docs.js create mode 100644 ui/scripts/network.js create mode 100755 ui/scripts/system.js diff --git a/api/src/main/java/com/cloud/network/Network.java b/api/src/main/java/com/cloud/network/Network.java index 0fee5c04d25c..31df22bf1895 100644 --- a/api/src/main/java/com/cloud/network/Network.java +++ b/api/src/main/java/com/cloud/network/Network.java @@ -202,6 +202,8 @@ public static class Provider { public static final Provider BigSwitchBcf = new Provider("BigSwitchBcf", false); //Add ConfigDrive provider public static final Provider ConfigDrive = new Provider("ConfigDrive", false); + //Add Tungsten provider + public static final Provider Tungsten = new Provider("Tungsten", true); private final String name; private final boolean isExternal; @@ -405,6 +407,10 @@ public void setIp6Address(String ip6Address) { TrafficType getTrafficType(); + String getTungstenNetworkUuid(); + + void setTungstenNetworkUuid(String tungstenNetworkUuid); + String getGateway(); // "cidr" is the Cloudstack managed address space, all CloudStack managed vms get IP address from "cidr", diff --git a/api/src/main/java/com/cloud/network/guru/NetworkGuruTungsten.java b/api/src/main/java/com/cloud/network/guru/NetworkGuruTungsten.java new file mode 100644 index 000000000000..41fdc3313fd0 --- /dev/null +++ b/api/src/main/java/com/cloud/network/guru/NetworkGuruTungsten.java @@ -0,0 +1,12 @@ +package com.cloud.network.guru; + +import com.cloud.network.Network; + +import java.util.List; + +public interface NetworkGuruTungsten { + Network createNetworkInTungsten(Network networkVO); + String createVirtualMachineInTungsten(String virtualMachineUuid, String virtualMachineName); + String createVmInterfaceInTungsten(String vmInterfaceName, String tungstenProjectUuid, String tungstenNetworkUuid, String tungstenVirtualMachineUuid, String tungstenSecurityGroupUuid, List tungstenVmInterfaceMacAddresses); + void createTungstenInstanceIp(String instanceIpName, String tungstenVmInterfaceUuid, String tungstenNetworkUuid, String tungstenInstanceIpAddress); +} diff --git a/api/src/main/java/com/cloud/offering/NetworkOffering.java b/api/src/main/java/com/cloud/offering/NetworkOffering.java index bf9044191769..ce165d645421 100644 --- a/api/src/main/java/com/cloud/offering/NetworkOffering.java +++ b/api/src/main/java/com/cloud/offering/NetworkOffering.java @@ -87,6 +87,8 @@ public enum Detail { boolean isForVpc(); + boolean isForTungsten(); + TrafficType getTrafficType(); boolean isSpecifyVlan(); diff --git a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java index eb8e9c6ec8e2..01ef33be6be8 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/admin/network/CreateNetworkOfferingCmd.java @@ -127,6 +127,11 @@ public class CreateNetworkOfferingCmd extends BaseCmd { description = "true if network offering is meant to be used for VPC, false otherwise.") private Boolean forVpc; + @Parameter(name = ApiConstants.FOR_TUNGSTEN, + type = CommandType.BOOLEAN, + description = "true if network offering is meant to be used for TUNGSTEN, false otherwise.") + private Boolean forTungsten; + @Parameter(name = ApiConstants.DETAILS, type = CommandType.MAP, since = "4.2.0", description = "Network offering details in key/value pairs." + " Supported keys are internallbprovider/publiclbprovider with service provider as a value, and" + " promiscuousmode/macaddresschanges/forgedtransmits with true/false as value to accept/reject the security settings if available for a nic/portgroup") @@ -240,6 +245,10 @@ public Boolean getForVpc() { return forVpc; } + public Boolean getForTungsten() { + return forTungsten; + } + public Boolean getEgressDefaultPolicy() { if (egressDefaultPolicy == null) { return true; diff --git a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java index 9973af2db9e4..11d6099e54bf 100644 --- a/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java +++ b/api/src/main/java/org/apache/cloudstack/api/command/user/network/CreateNetworkCmd.java @@ -64,34 +64,34 @@ public class CreateNetworkCmd extends BaseCmd implements UserCmd { private String displayText; @Parameter(name = ApiConstants.NETWORK_OFFERING_ID, - type = CommandType.UUID, - entityType = NetworkOfferingResponse.class, - required = true, - description = "the network offering ID") + type = CommandType.UUID, + entityType = NetworkOfferingResponse.class, + required = true, + description = "the network offering ID") private Long networkOfferingId; @Parameter(name = ApiConstants.ZONE_ID, type = CommandType.UUID, entityType = ZoneResponse.class, required = true, description = "the zone ID for the network") private Long zoneId; @Parameter(name = ApiConstants.PHYSICAL_NETWORK_ID, - type = CommandType.UUID, - entityType = PhysicalNetworkResponse.class, - description = "the physical network ID the network belongs to") + type = CommandType.UUID, + entityType = PhysicalNetworkResponse.class, + description = "the physical network ID the network belongs to") private Long physicalNetworkId; @Parameter(name = ApiConstants.GATEWAY, type = CommandType.STRING, description = "the gateway of the network. Required " - + "for shared networks and isolated networks when it belongs to VPC") + + "for shared networks and isolated networks when it belongs to VPC") private String gateway; @Parameter(name = ApiConstants.NETMASK, type = CommandType.STRING, description = "the netmask of the network. Required " - + "for shared networks and isolated networks when it belongs to VPC") + + "for shared networks and isolated networks when it belongs to VPC") private String netmask; @Parameter(name = ApiConstants.START_IP, type = CommandType.STRING, description = "the beginning IP address in the network IP range") private String startIp; @Parameter(name = ApiConstants.END_IP, type = CommandType.STRING, description = "the ending IP address in the network IP" - + " range. If not specified, will be defaulted to startIP") + + " range. If not specified, will be defaulted to startIP") private String endIp; @Parameter(name = ApiConstants.ISOLATED_PVLAN, type = CommandType.STRING, description = "the isolated private VLAN for this network") @@ -105,28 +105,31 @@ public class CreateNetworkCmd extends BaseCmd implements UserCmd { private String networkDomain; @Parameter(name = ApiConstants.ACL_TYPE, type = CommandType.STRING, description = "Access control type; supported values" - + " are account and domain. In 3.0 all shared networks should have aclType=Domain, and all isolated networks" - + " - Account. Account means that only the account owner can use the network, domain - all accounts in the domain can use the network") + + " are account and domain. In 3.0 all shared networks should have aclType=Domain, and all isolated networks" + + " - Account. Account means that only the account owner can use the network, domain - all accounts in the domain can use the network") private String aclType; @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "account that will own the network") private String accountName; - @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "an optional project for the network") + @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "an optional project for the SSH key") private Long projectId; @Parameter(name = ApiConstants.DOMAIN_ID, type = CommandType.UUID, entityType = DomainResponse.class, description = "domain ID of the account owning a network") private Long domainId; @Parameter(name = ApiConstants.SUBDOMAIN_ACCESS, - type = CommandType.BOOLEAN, - description = "Defines whether to allow" - + " subdomains to use networks dedicated to their parent domain(s). Should be used with aclType=Domain, defaulted to allow.subdomain.network.access global config if not specified") + type = CommandType.BOOLEAN, + description = "Defines whether to allow" + + " subdomains to use networks dedicated to their parent domain(s). Should be used with aclType=Domain, defaulted to allow.subdomain.network.access global config if not specified") private Boolean subdomainAccess; @Parameter(name = ApiConstants.VPC_ID, type = CommandType.UUID, entityType = VpcResponse.class, description = "the VPC network belongs to") private Long vpcId; + @Parameter(name = ApiConstants.TUNGSTEN_VIRTUAL_ROUTER_UUID, type = CommandType.STRING, description = "tungsten virtual router the network belongs to") + private String tungstenVirtualRouterUuid; + @Parameter(name = ApiConstants.START_IPV6, type = CommandType.STRING, description = "the beginning IPv6 address in the IPv6 network range") private String startIpv6; @@ -143,32 +146,16 @@ public class CreateNetworkCmd extends BaseCmd implements UserCmd { private String externalId; @Parameter(name = ApiConstants.DISPLAY_NETWORK, - type = CommandType.BOOLEAN, - description = "an optional field, whether to the display the network to the end user or not.", authorized = {RoleType.Admin}) + type = CommandType.BOOLEAN, + description = "an optional field, whether to the display the network to the end user or not.", authorized = {RoleType.Admin}) private Boolean displayNetwork; + @Parameter(name = ApiConstants.IS_TUNGSTEN_NETWORK, type = CommandType.UUID, description = "tungsten network belongs to") + private Long tungstenNetwork; + @Parameter(name = ApiConstants.ACL_ID, type = CommandType.UUID, entityType = NetworkACLResponse.class, description = "Network ACL ID associated for the network") private Long aclId; - @Parameter(name = ApiConstants.ASSOCIATED_NETWORK_ID, - type = CommandType.UUID, - entityType = NetworkResponse.class, - since = "4.17.0", - description = "The network this network is associated to. only available if create a Shared network") - private Long associatedNetworkId; - - @Parameter(name = ApiConstants.DNS1, type = CommandType.STRING, description = "the first IPv4 DNS for the network", since = "4.18.0") - private String ip4Dns1; - - @Parameter(name = ApiConstants.DNS2, type = CommandType.STRING, description = "the second IPv4 DNS for the network", since = "4.18.0") - private String ip4Dns2; - - @Parameter(name = ApiConstants.IP6_DNS1, type = CommandType.STRING, description = "the first IPv6 DNS for the network", since = "4.18.0") - private String ip6Dns1; - - @Parameter(name = ApiConstants.IP6_DNS2, type = CommandType.STRING, description = "the second IPv6 DNS for the network", since = "4.18.0") - private String ip6Dns2; - ///////////////////////////////////////////////////// /////////////////// Accessors /////////////////////// ///////////////////////////////////////////////////// @@ -244,8 +231,12 @@ public String getIsolatedPvlanType() { return isolatedPvlanType; } - public Long getAssociatedNetworkId() { - return associatedNetworkId; + public Long isTungstenNetwork() { + return tungstenNetwork; + } + + public String getTungstenVirtualRouterUuid() { + return tungstenVirtualRouterUuid; } @Override @@ -272,31 +263,11 @@ public Long getPhysicalNetworkId() { throw new InvalidParameterValueException("Unable to find network offering by ID " + networkOfferingId); } - Network associatedNetwork = null; - if (associatedNetworkId != null) { - associatedNetwork = _entityMgr.findById(Network.class, associatedNetworkId); - if (associatedNetwork == null) { - throw new InvalidParameterValueException("Unable to find network by ID " + associatedNetworkId); - } - if (offering.getGuestType() != GuestType.Shared) { - throw new InvalidParameterValueException("Associated network ID can be specified for networks of guest IP type " + GuestType.Shared + " only."); - } - if (zoneId != null && associatedNetwork.getDataCenterId() != zoneId) { - throw new InvalidParameterValueException("The network can only be created in the same zone as the associated network"); - } else if (zoneId == null) { - zoneId = associatedNetwork.getDataCenterId(); - } - if (physicalNetworkId != null && !physicalNetworkId.equals(associatedNetwork.getPhysicalNetworkId())) { - throw new InvalidParameterValueException("The network can only be created on the same physical network as the associated network"); - } else if (physicalNetworkId == null) { - physicalNetworkId = associatedNetwork.getPhysicalNetworkId(); - } - } if (physicalNetworkId != null) { if (offering.getGuestType() == GuestType.Shared) { return physicalNetworkId; } else { - throw new InvalidParameterValueException("Physical network ID can be specified for networks of guest IP type " + GuestType.Shared + " only."); + throw new InvalidParameterValueException("Physical network OD can be specified for networks of guest IP type " + GuestType.Shared + " only."); } } else { if (zoneId == null) { @@ -338,22 +309,6 @@ public Long getAclId() { return aclId; } - public String getIp4Dns1() { - return ip4Dns1; - } - - public String getIp4Dns2() { - return ip4Dns2; - } - - public String getIp6Dns1() { - return ip6Dns1; - } - - public String getIp6Dns2() { - return ip6Dns2; - } - ///////////////////////////////////////////////////// /////////////// API Implementation/////////////////// ///////////////////////////////////////////////////// @@ -374,7 +329,8 @@ public long getEntityOwnerId() { @Override // an exception thrown by createNetwork() will be caught by the dispatcher. - public void execute() throws InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException { + public + void execute() throws InsufficientCapacityException, ConcurrentOperationException, ResourceAllocationException { Network result = _networkService.createGuestNetwork(this); if (result != null) { NetworkResponse response = _responseGenerator.createNetworkResponse(getResponseView(), result); diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java index 17fe1e0d7415..0e30e3e43d4a 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkOfferingResponse.java @@ -99,6 +99,10 @@ public class NetworkOfferingResponse extends BaseResponseWithAnnotations { @Param(description = "true if network offering can be used by VPC networks only") private Boolean forVpc; + @SerializedName(ApiConstants.FOR_TUNGSTEN) + @Param(description = "true if network offering can be used by tungsten networks only") + private Boolean forTungsten; + @SerializedName(ApiConstants.IS_PERSISTENT) @Param(description = "true if network offering supports persistent networks, false otherwise") private Boolean isPersistent; @@ -211,6 +215,10 @@ public void setForVpc(Boolean forVpc) { this.forVpc = forVpc; } + public void setForTungsten(Boolean forTungsten) { + this.forTungsten = forTungsten; + } + public void setIsPersistent(Boolean isPersistent) { this.isPersistent = isPersistent; } diff --git a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java index 19edc1b3944f..b1db481be0b4 100644 --- a/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java +++ b/api/src/main/java/org/apache/cloudstack/api/response/NetworkResponse.java @@ -16,14 +16,13 @@ // under the License. package org.apache.cloudstack.api.response; -import java.util.Date; import java.util.List; import java.util.Map; import java.util.Set; import org.apache.cloudstack.acl.RoleType; import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.api.BaseResponseWithAssociatedNetwork; +import org.apache.cloudstack.api.BaseResponse; import org.apache.cloudstack.api.EntityReference; import com.cloud.network.Network; @@ -33,7 +32,7 @@ @SuppressWarnings("unused") @EntityReference(value = {Network.class, ProjectAccount.class}) -public class NetworkResponse extends BaseResponseWithAssociatedNetwork implements ControlledEntityResponse, SetResourceIconResponse { +public class NetworkResponse extends BaseResponse implements ControlledEntityResponse { @SerializedName(ApiConstants.ID) @Param(description = "the id of the network") @@ -120,11 +119,11 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement private String broadcastUri; @SerializedName(ApiConstants.DNS1) - @Param(description = "the first IPv4 DNS for the network") + @Param(description = "the first DNS for the network") private String dns1; @SerializedName(ApiConstants.DNS2) - @Param(description = "the second IPv4 DNS for the network") + @Param(description = "the second DNS for the network") private String dns2; @SerializedName(ApiConstants.TYPE) @@ -191,17 +190,9 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement @Param(description = "VPC the network belongs to") private String vpcId; - @SerializedName(ApiConstants.VPC_NAME) - @Param(description = "Name of the VPC to which this network belongs", since = "4.15") - private String vpcName; - - @SerializedName(ApiConstants.ASSOCIATED_NETWORK_ID) - @Param(description = "the ID of the Network associated with this network") - private String associatedNetworkId; - - @SerializedName(ApiConstants.ASSOCIATED_NETWORK) - @Param(description = "the name of the Network associated with this network") - private String associatedNetworkName; + @SerializedName(ApiConstants.TUNGSTEN_VIRTUAL_ROUTER_UUID) + @Param(description = "Tungsten virtual router the network belongs to") + private String tungstenVirtualRouterUuid; @SerializedName(ApiConstants.CAN_USE_FOR_DEPLOY) @Param(description = "list networks available for vm deployment") @@ -235,10 +226,6 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement @Param(description = "ACL Id associated with the VPC network") private String aclId; - @SerializedName(ApiConstants.ACL_NAME) - @Param(description = "ACL name associated with the VPC network") - private String aclName; - @SerializedName(ApiConstants.STRECHED_L2_SUBNET) @Param(description = "true if network can span multiple zones", since = "4.4") private Boolean strechedL2Subnet; @@ -255,48 +242,6 @@ public class NetworkResponse extends BaseResponseWithAssociatedNetwork implement @Param(description = "If the network has redundant routers enabled", since = "4.11.1") private Boolean redundantRouter; - @SerializedName(ApiConstants.RESOURCE_ICON) - @Param(description = "Base64 string representation of the resource icon", since = "4.16.0.0") - ResourceIconResponse icon; - - @SerializedName(ApiConstants.CREATED) - @Param(description = "the date this network was created", since = "4.16.0") - private Date created; - - @SerializedName(ApiConstants.RECEIVED_BYTES) - @Param(description = "the total number of network traffic bytes received") - private Long bytesReceived; - - @SerializedName(ApiConstants.SENT_BYTES) - @Param(description = "the total number of network traffic bytes sent") - private Long bytesSent; - - @SerializedName((ApiConstants.EGRESS_DEFAULT_POLICY)) - @Param(description = "true if guest network default egress policy is allow; false if default egress policy is deny") - private Boolean egressDefaultPolicy; - - @SerializedName(ApiConstants.INTERNET_PROTOCOL) - @Param(description = "The internet protocol of network offering") - private String internetProtocol; - - @SerializedName(ApiConstants.IPV6_ROUTING) - @Param(description = "The routing mode of network offering", since = "4.17.0") - private String ipv6Routing; - - @SerializedName(ApiConstants.IPV6_ROUTES) - @Param(description = "The routes for the network to ease adding route in upstream router", since = "4.17.0") - private Set ipv6Routes; - - @SerializedName(ApiConstants.IP6_DNS1) - @Param(description = "the first IPv6 DNS for the network", since = "4.18.0") - private String ipv6Dns1; - - @SerializedName(ApiConstants.IP6_DNS2) - @Param(description = "the second IPv6 DNS for the network", since = "4.18.0") - private String ipv6Dns2; - - public NetworkResponse() {} - public Boolean getDisplayNetwork() { return displayNetwork; } @@ -309,10 +254,6 @@ public void setId(String id) { this.id = id; } - public String getId() { - return id; - } - public void setName(String name) { this.name = name; } @@ -470,10 +411,6 @@ public void setVpcId(String vpcId) { this.vpcId = vpcId; } - public String getVpcId() { - return vpcId; - } - public void setCanUseForDeploy(Boolean canUseForDeploy) { this.canUseForDeploy = canUseForDeploy; } @@ -506,14 +443,6 @@ public void setAclId(String aclId) { this.aclId = aclId; } - public String getAclName() { - return aclName; - } - - public void setAclName(String aclName) { - this.aclName = aclName; - } - public void setStrechedL2Subnet(Boolean strechedL2Subnet) { this.strechedL2Subnet = strechedL2Subnet; } @@ -534,72 +463,11 @@ public void setRedundantRouter(Boolean redundantRouter) { this.redundantRouter = redundantRouter; } - public String getVpcName() { - return vpcName; - } - - public void setVpcName(String vpcName) { - this.vpcName = vpcName; - } - - public void setAssociatedNetworkId(String associatedNetworkId) { - this.associatedNetworkId = associatedNetworkId; - } - - public void setAssociatedNetworkName(String associatedNetworkName) { - this.associatedNetworkName = associatedNetworkName; - } - - @Override - public void setResourceIconResponse(ResourceIconResponse icon) { - this.icon = icon; - } - - public Date getCreated() { - return created; - } - - public void setCreated(Date created) { - this.created = created; - } - - public void setBytesReceived(Long bytesReceived) { - this.bytesReceived = bytesReceived; - } - - public void setBytesSent(final Long bytesSent) { - this.bytesSent = bytesSent; - } - - public boolean getEgressDefaultPolicy() { - return egressDefaultPolicy; - } - - public void setEgressDefaultPolicy(Boolean egressDefaultPolicy) { - this.egressDefaultPolicy = egressDefaultPolicy; - } - - public void setInternetProtocol(String internetProtocol) { - this.internetProtocol = internetProtocol; - } - - public void setIpv6Routing(String ipv6Routing) { - this.ipv6Routing = ipv6Routing; - } - - public void setIpv6Routes(Set ipv6Routes) { - this.ipv6Routes = ipv6Routes; - } - - public void addIpv6Route(Ipv6RouteResponse ipv6Route) { - this.ipv6Routes.add(ipv6Route); - } - - public void setIpv6Dns1(String ipv6Dns1) { - this.ipv6Dns1 = ipv6Dns1; + public String getTungstenVirtualRouterUuid() { + return tungstenVirtualRouterUuid; } - public void setIpv6Dns2(String ipv6Dns2) { - this.ipv6Dns2 = ipv6Dns2; + public void setTungstenVirtualRouterUuid(String tungstenVirtualRouterUuid) { + this.tungstenVirtualRouterUuid = tungstenVirtualRouterUuid; } } diff --git a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java index 0442cac86c8e..c85f0bb7510b 100644 --- a/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java +++ b/engine/components-api/src/main/java/com/cloud/configuration/ConfigurationManager.java @@ -42,7 +42,6 @@ import com.cloud.offerings.NetworkOfferingVO; import com.cloud.org.Grouping.AllocationState; import com.cloud.user.Account; -import com.cloud.utils.net.NetUtils; /** * ConfigurationManager handles adding pods/zones, changing IP ranges, enabling external firewalls, and editing @@ -138,7 +137,7 @@ public interface ConfigurationManager { * @return Pod */ HostPodVO createPod(long userId, String podName, long zoneId, String gateway, String cidr, String startIp, String endIp, String allocationState, - boolean skipGatewayOverlapCheck); + boolean skipGatewayOverlapCheck); /** * Creates a new zone @@ -163,8 +162,8 @@ HostPodVO createPod(long userId, String podName, long zoneId, String gateway, St * @throws */ DataCenterVO createZone(long userId, String zoneName, String dns1, String dns2, String internalDns1, String internalDns2, String guestCidr, String domain, - Long domainId, NetworkType zoneType, String allocationState, String networkDomain, boolean isSecurityGroupEnabled, boolean isLocalStorageEnabled, String ip6Dns1, - String ip6Dns2); + Long domainId, NetworkType zoneType, String allocationState, String networkDomain, boolean isSecurityGroupEnabled, boolean isLocalStorageEnabled, String ip6Dns1, + String ip6Dns2); /** * Deletes a VLAN from the database, along with all of its IP addresses. Will not delete VLANs that have allocated @@ -215,12 +214,11 @@ DataCenterVO createZone(long userId, String zoneName, String dns1, String dns2, NetworkOfferingVO createNetworkOffering(String name, String displayText, TrafficType trafficType, String tags, boolean specifyVlan, Availability availability, Integer networkRate, Map> serviceProviderMap, boolean isDefault, Network.GuestType type, boolean systemOnly, Long serviceOfferingId, boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, - Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, - List domainIds, List zoneIds, boolean enableOffering, final NetUtils.InternetProtocol internetProtocol); + Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, Boolean forTungsten, List domainIds, List zoneIds); Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, boolean forSystemVms, Long podId, String startIP, String endIP, - String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr) - throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException; + String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanIp6Gateway, String vlanIp6Cidr) + throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException; void createDefaultSystemNetworks(long zoneId) throws ConcurrentOperationException; @@ -254,7 +252,7 @@ Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetwor * @throws * @throws */ - Pod editPod(long id, String name, String startIp, String endIp, String gateway, String netmask, String allocationState); + Pod editPod(long id, String name, String startIp, String endIp, String gateway, String netmask, String allocationStateStr); void checkPodCidrSubnets(long zoneId, Long podIdToBeSkipped, String cidr); diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index fcacc14d35c5..ca21d53b16c3 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -16,48 +16,6 @@ // under the License. package org.apache.cloudstack.engine.orchestration; -import java.net.URI; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collections; -import java.util.Comparator; -import java.util.Date; -import java.util.HashMap; -import java.util.HashSet; -import java.util.LinkedHashMap; -import java.util.LinkedList; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.UUID; -import java.util.concurrent.Executors; -import java.util.concurrent.ScheduledExecutorService; -import java.util.concurrent.TimeUnit; -import java.util.stream.Collectors; - -import javax.inject.Inject; -import javax.naming.ConfigurationException; - -import org.apache.cloudstack.acl.ControlledEntity.ACLType; -import org.apache.cloudstack.annotation.AnnotationService; -import org.apache.cloudstack.annotation.dao.AnnotationDao; -import org.apache.cloudstack.api.ApiConstants; -import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.engine.cloud.entity.api.db.VMNetworkMapVO; -import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMNetworkMapDao; -import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; -import org.apache.cloudstack.framework.config.ConfigKey; -import org.apache.cloudstack.framework.config.ConfigKey.Scope; -import org.apache.cloudstack.framework.config.Configurable; -import org.apache.cloudstack.framework.config.dao.ConfigurationDao; -import org.apache.cloudstack.framework.messagebus.MessageBus; -import org.apache.cloudstack.framework.messagebus.PublishScope; -import org.apache.cloudstack.managed.context.ManagedContextRunnable; -import org.apache.cloudstack.network.dao.NetworkPermissionDao; -import org.apache.commons.collections.CollectionUtils; -import org.apache.commons.lang3.BooleanUtils; -import org.apache.commons.lang3.StringUtils; -import org.apache.log4j.Logger; import com.cloud.agent.AgentManager; import com.cloud.agent.Listener; @@ -66,20 +24,14 @@ import com.cloud.agent.api.Answer; import com.cloud.agent.api.CheckNetworkAnswer; import com.cloud.agent.api.CheckNetworkCommand; -import com.cloud.agent.api.CleanupPersistentNetworkResourceAnswer; -import com.cloud.agent.api.CleanupPersistentNetworkResourceCommand; import com.cloud.agent.api.Command; -import com.cloud.agent.api.SetupPersistentNetworkAnswer; -import com.cloud.agent.api.SetupPersistentNetworkCommand; import com.cloud.agent.api.StartupCommand; import com.cloud.agent.api.StartupRoutingCommand; import com.cloud.agent.api.routing.NetworkElementCommand; import com.cloud.agent.api.to.NicTO; -import com.cloud.agent.api.to.deployasis.OVFNetworkTO; import com.cloud.alert.AlertManager; import com.cloud.configuration.ConfigurationManager; import com.cloud.configuration.Resource.ResourceType; -import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.DataCenterVO; @@ -87,7 +39,6 @@ import com.cloud.dc.PodVlanMapVO; import com.cloud.dc.Vlan; import com.cloud.dc.VlanVO; -import com.cloud.dc.dao.ClusterDao; import com.cloud.dc.dao.DataCenterDao; import com.cloud.dc.dao.DataCenterVnetDao; import com.cloud.dc.dao.PodVlanMapDao; @@ -95,29 +46,24 @@ import com.cloud.deploy.DataCenterDeployment; import com.cloud.deploy.DeployDestination; import com.cloud.deploy.DeploymentPlan; -import com.cloud.deployasis.dao.TemplateDeployAsIsDetailsDao; import com.cloud.domain.Domain; import com.cloud.event.EventTypes; import com.cloud.event.UsageEventUtils; -import com.cloud.exception.AgentUnavailableException; import com.cloud.exception.ConcurrentOperationException; import com.cloud.exception.ConnectionException; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapacityException; import com.cloud.exception.InvalidParameterValueException; -import com.cloud.exception.OperationTimedoutException; import com.cloud.exception.ResourceAllocationException; import com.cloud.exception.ResourceUnavailableException; import com.cloud.exception.UnsupportedServiceException; import com.cloud.host.Host; -import com.cloud.host.HostVO; import com.cloud.host.Status; import com.cloud.host.dao.HostDao; import com.cloud.hypervisor.Hypervisor.HypervisorType; import com.cloud.network.IpAddress; import com.cloud.network.IpAddressManager; -import com.cloud.network.Ipv6Service; import com.cloud.network.Network; import com.cloud.network.Network.Capability; import com.cloud.network.Network.Event; @@ -158,7 +104,6 @@ import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.dao.RemoteAccessVpnDao; import com.cloud.network.dao.RemoteAccessVpnVO; -import com.cloud.network.dao.RouterNetworkDao; import com.cloud.network.element.AggregatedCommandExecutor; import com.cloud.network.element.ConfigDriveNetworkElement; import com.cloud.network.element.DhcpServiceProvider; @@ -172,6 +117,7 @@ import com.cloud.network.element.VirtualRouterElement; import com.cloud.network.guru.NetworkGuru; import com.cloud.network.guru.NetworkGuruAdditionalFunctions; +import com.cloud.network.guru.NetworkGuruTungsten; import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallManager; @@ -196,14 +142,13 @@ import com.cloud.offerings.dao.NetworkOfferingDao; import com.cloud.offerings.dao.NetworkOfferingDetailsDao; import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; -import com.cloud.resource.ResourceManager; -import com.cloud.server.ManagementServer; import com.cloud.user.Account; import com.cloud.user.ResourceLimitService; import com.cloud.user.User; import com.cloud.user.dao.AccountDao; import com.cloud.utils.NumbersUtil; import com.cloud.utils.Pair; +import com.cloud.utils.StringUtils; import com.cloud.utils.UuidUtils; import com.cloud.utils.component.AdapterBase; import com.cloud.utils.component.ManagerBase; @@ -233,7 +178,6 @@ import com.cloud.vm.NicVO; import com.cloud.vm.ReservationContext; import com.cloud.vm.ReservationContextImpl; -import com.cloud.vm.UserVmManager; import com.cloud.vm.UserVmVO; import com.cloud.vm.VMInstanceVO; import com.cloud.vm.VirtualMachine; @@ -248,7 +192,45 @@ import com.cloud.vm.dao.NicSecondaryIpVO; import com.cloud.vm.dao.UserVmDao; import com.cloud.vm.dao.VMInstanceDao; -import com.googlecode.ipv6.IPv6Address; +import com.google.common.base.Strings; +import org.apache.cloudstack.acl.ControlledEntity.ACLType; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.engine.cloud.entity.api.db.VMNetworkMapVO; +import org.apache.cloudstack.engine.cloud.entity.api.db.dao.VMNetworkMapDao; +import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; +import org.apache.cloudstack.framework.config.ConfigKey; +import org.apache.cloudstack.framework.config.ConfigKey.Scope; +import org.apache.cloudstack.framework.config.Configurable; +import org.apache.cloudstack.framework.config.dao.ConfigurationDao; +import org.apache.cloudstack.framework.messagebus.MessageBus; +import org.apache.cloudstack.framework.messagebus.PublishScope; +import org.apache.cloudstack.managed.context.ManagedContextRunnable; +import org.apache.commons.lang.BooleanUtils; +import org.apache.log4j.Logger; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.net.URI; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Comparator; +import java.util.Date; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.UUID; +import java.util.concurrent.Executors; +import java.util.concurrent.ScheduledExecutorService; +import java.util.concurrent.TimeUnit; +import java.util.stream.Collectors; + +import static org.apache.commons.lang.StringUtils.isNotBlank; /** * NetworkManagerImpl implements NetworkManager. @@ -311,27 +293,11 @@ public class NetworkOrchestrator extends ManagerBase implements NetworkOrchestra @Inject VMNetworkMapDao _vmNetworkMapDao; @Inject - DomainRouterDao routerDao; + DomainRouterDao _routerDao; @Inject RemoteAccessVpnDao _remoteAccessVpnDao; @Inject VpcVirtualNetworkApplianceService _routerService; - @Inject - UserVmManager _userVmMgr; - @Inject - TemplateDeployAsIsDetailsDao templateDeployAsIsDetailsDao; - @Inject - ResourceManager resourceManager; - @Inject - private AnnotationDao annotationDao; - @Inject - public ManagementServer mgr; - @Inject - NetworkPermissionDao networkPermissionDao; - @Inject - Ipv6Service ipv6Service; - @Inject - RouterNetworkDao routerNetworkDao; List networkGurus; @@ -412,8 +378,6 @@ public void setDhcpProviders(final List dhcpProviders) { NetworkModel _networkModel; @Inject NicSecondaryIpDao _nicSecondaryIpDao; - @Inject - ClusterDao clusterDao; protected StateMachine2 _stateMachine; ScheduledExecutorService _executor; @@ -423,38 +387,6 @@ public void setDhcpProviders(final List dhcpProviders) { HashMap _lastNetworkIdsToFree = new HashMap(); - private void updateRouterDefaultDns(final VirtualMachineProfile vmProfile, final NicProfile nicProfile) { - if (!Type.DomainRouter.equals(vmProfile.getType()) || !nicProfile.isDefaultNic()) { - return; - } - DomainRouterVO router = routerDao.findById(vmProfile.getId()); - if (router != null && router.getVpcId() != null) { - final Vpc vpc = _vpcMgr.getActiveVpc(router.getVpcId()); - if (StringUtils.isNotBlank(vpc.getIp4Dns1())) { - nicProfile.setIPv4Dns1(vpc.getIp4Dns1()); - nicProfile.setIPv4Dns2(vpc.getIp4Dns2()); - } - if (StringUtils.isNotBlank(vpc.getIp6Dns1())) { - nicProfile.setIPv6Dns1(vpc.getIp6Dns1()); - nicProfile.setIPv6Dns2(vpc.getIp6Dns2()); - } - return; - } - List networkIds = routerNetworkDao.getRouterNetworks(vmProfile.getId()); - if (CollectionUtils.isEmpty(networkIds) || networkIds.size() > 1) { - return; - } - final NetworkVO routerNetwork = _networksDao.findById(networkIds.get(0)); - if (StringUtils.isNotBlank(routerNetwork.getDns1())) { - nicProfile.setIPv4Dns1(routerNetwork.getDns1()); - nicProfile.setIPv4Dns2(routerNetwork.getDns2()); - } - if (StringUtils.isNotBlank(routerNetwork.getIp6Dns1())) { - nicProfile.setIPv6Dns1(routerNetwork.getIp6Dns1()); - nicProfile.setIPv6Dns2(routerNetwork.getIp6Dns2()); - } - } - @Override @DB public boolean configure(final String name, final Map params) throws ConfigurationException { @@ -522,21 +454,27 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { if (_networkOfferingDao.findByUniqueName(NetworkOffering.QuickCloudNoServices) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.QuickCloudNoServices, "Offering for QuickCloud with no services", TrafficType.Guest, null, true, Availability.Optional, null, new HashMap>(), true, Network.GuestType.Shared, false, null, true, null, true, - false, null, false, null, true, false, null, null, true, null); + false, null, false, null, true, false, false,null, null); + offering.setState(NetworkOffering.State.Enabled); + _networkOfferingDao.update(offering.getId(), offering); } //#2 - SG enabled network offering if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOfferingWithSGService) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOfferingWithSGService, "Offering for Shared Security group enabled networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, - null, true, false, null, false, null, true, false, null, null, true, null); + null, true, false, null, false, null, true, false, false,null, null); + offering.setState(NetworkOffering.State.Enabled); + _networkOfferingDao.update(offering.getId(), offering); } //#3 - shared network offering with no SG service if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedNetworkOffering, "Offering for Shared networks", TrafficType.Guest, null, true, Availability.Optional, null, defaultSharedNetworkOfferingProviders, true, Network.GuestType.Shared, false, null, true, null, true, false, null, false, - null, true, false, null, null, true, null); + null, true, false, false,null, null); + offering.setState(NetworkOffering.State.Enabled); + _networkOfferingDao.update(offering.getId(), offering); } //#4 - default isolated offering with Source nat service @@ -544,14 +482,19 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingWithSourceNatService, "Offering for Isolated networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Required, null, defaultIsolatedSourceNatEnabledNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, true, null, false, false, null, false, null, - true, false, null, null, true, null); + true, false, false,null, null); + + offering.setState(NetworkOffering.State.Enabled); + _networkOfferingDao.update(offering.getId(), offering); } //#5 - default vpc offering with LB service if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworks, "Offering for Isolated VPC networks with Source Nat service enabled", TrafficType.Guest, null, false, Availability.Optional, null, - defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null, true, null); + defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false,null, null); + offering.setState(NetworkOffering.State.Enabled); + _networkOfferingDao.update(offering.getId(), offering); } //#6 - default vpc offering with no LB service @@ -560,14 +503,18 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { defaultVPCOffProviders.remove(Service.Lb); offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksNoLB, "Offering for Isolated VPC networks with Source Nat service enabled and LB service disabled", TrafficType.Guest, null, false, Availability.Optional, - null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null, true, null); + null, defaultVPCOffProviders, true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false,null, null); + offering.setState(NetworkOffering.State.Enabled); + _networkOfferingDao.update(offering.getId(), offering); } //#7 - isolated offering with source nat disabled if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOffering, "Offering for Isolated networks with no Source Nat service", TrafficType.Guest, null, true, Availability.Optional, null, defaultIsolatedNetworkOfferingProviders, true, Network.GuestType.Isolated, false, null, - true, null, true, false, null, false, null, true, false, null, null, true, null); + true, null, true, false, null, false, null, true, false, false,null, null); + offering.setState(NetworkOffering.State.Enabled); + _networkOfferingDao.update(offering.getId(), offering); } //#8 - network offering with internal lb service @@ -589,7 +536,8 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultIsolatedNetworkOfferingForVpcNetworksWithInternalLB, "Offering for Isolated VPC networks with Internal Lb support", TrafficType.Guest, null, false, Availability.Optional, null, internalLbOffProviders, - true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null, true, null); + true, Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false,null, null); + offering.setState(NetworkOffering.State.Enabled); offering.setInternalLb(true); offering.setPublicLb(false); _networkOfferingDao.update(offering.getId(), offering); @@ -620,7 +568,8 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { if (_networkOfferingDao.findByUniqueName(NetworkOffering.DefaultSharedEIPandELBNetworkOffering) == null) { offering = _configMgr.createNetworkOffering(NetworkOffering.DefaultSharedEIPandELBNetworkOffering, "Offering for Shared networks with Elastic IP and Elastic LB capabilities", TrafficType.Guest, null, true, Availability.Optional, null, - netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true, false, null, null, true, null); + netscalerServiceProviders, true, Network.GuestType.Shared, false, null, true, serviceCapabilityMap, true, false, null, false, null, true, false, false,null, null); + offering.setState(NetworkOffering.State.Enabled); offering.setDedicatedLB(false); _networkOfferingDao.update(offering.getId(), offering); } @@ -684,15 +633,6 @@ protected NetworkOrchestrator() { setStateMachine(); } - private void updateRouterIpInNetworkDetails(Long networkId, String routerIp, String routerIpv6) { - if (StringUtils.isNotBlank(routerIp)) { - networkDetailsDao.addDetail(networkId, ApiConstants.ROUTER_IP, routerIp, true); - } - if (StringUtils.isNotBlank(routerIpv6)) { - networkDetailsDao.addDetail(networkId, ApiConstants.ROUTER_IPV6, routerIpv6, true); - } - } - @Override public List setupNetwork(final Account owner, final NetworkOffering offering, final DeploymentPlan plan, final String name, final String displayText, final boolean isDefault) throws ConcurrentOperationException { @@ -745,7 +685,7 @@ public List setupNetwork(final Account owner, final NetworkOf if (network.getId() != -1) { if (network instanceof NetworkVO) { - networks.add((NetworkVO) network); + networks.add((NetworkVO)network); } else { networks.add(_networksDao.findById(network.getId())); } @@ -761,11 +701,16 @@ public List setupNetwork(final Account owner, final NetworkOf Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(final TransactionStatus status) { - final NetworkVO vo = new NetworkVO(id, network, offering.getId(), guru.getName(), owner.getDomainId(), owner.getId(), relatedFile, name, displayText, predefined + NetworkVO vo = new NetworkVO(id, network, offering.getId(), guru.getName(), owner.getDomainId(), owner.getId(), relatedFile, name, displayText, predefined .getNetworkDomain(), offering.getGuestType(), plan.getDataCenterId(), plan.getPhysicalNetworkId(), aclType, offering.isSpecifyIpRanges(), vpcId, offering.isRedundantRouter(), predefined.getExternalId()); vo.setDisplayNetwork(isDisplayNetworkEnabled == null ? true : isDisplayNetworkEnabled); vo.setStrechedL2Network(offering.isSupportingStrechedL2()); + + if(guru instanceof NetworkGuruTungsten){ + vo = (NetworkVO) ((NetworkGuruTungsten) guru).createNetworkInTungsten(vo); + } + final NetworkVO networkPersisted = _networksDao.persist(vo, vo.getGuestType() == Network.GuestType.Isolated, finalizeServicesAndProvidersForNetwork(offering, plan.getPhysicalNetworkId())); networks.add(networkPersisted); @@ -775,11 +720,9 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { networkDetailsDao.persist(detailVO); } - updateRouterIpInNetworkDetails(networkPersisted.getId(), network.getRouterIp(), network.getRouterIpv6()); - - if (predefined instanceof NetworkVO && guru instanceof NetworkGuruAdditionalFunctions) { + if (predefined instanceof NetworkVO && guru instanceof NetworkGuruAdditionalFunctions){ final NetworkGuruAdditionalFunctions functions = (NetworkGuruAdditionalFunctions) guru; - functions.finalizeNetworkDesign(networkPersisted.getId(), ((NetworkVO) predefined).getVlanIdAsUUID()); + functions.finalizeNetworkDesign(networkPersisted.getId(), ((NetworkVO)predefined).getVlanIdAsUUID()); } if (domainId != null && aclType == ACLType.Domain) { @@ -811,91 +754,25 @@ public void allocate(final VirtualMachineProfile vm, final LinkedHashMap() { @Override public void doInTransactionWithoutResult(final TransactionStatus status) throws InsufficientCapacityException { - if (s_logger.isTraceEnabled()) { - s_logger.trace(String.format("allocating networks for %s(template %s); %d networks", vm.getInstanceName(), vm.getTemplate().getUuid(), networks.size())); - } int deviceId = 0; - int size; - size = determineNumberOfNicsRequired(); + int size = 0; + for (final Network ntwk : networks.keySet()) { + final List profiles = networks.get(ntwk); + if (profiles != null && !profiles.isEmpty()) { + size = size + profiles.size(); + } else { + size = size + 1; + } + } final boolean[] deviceIds = new boolean[size]; Arrays.fill(deviceIds, false); - List> profilesList = getOrderedNetworkNicProfileMapping(networks); final List nics = new ArrayList(size); NicProfile defaultNic = null; - Network nextNetwork = null; - for (Pair networkNicPair : profilesList) { - nextNetwork = networkNicPair.first(); - Pair newDeviceInfo = addRequestedNicToNicListWithDeviceNumberAndRetrieveDefaultDevice(networkNicPair.second(), deviceIds, deviceId, nextNetwork, nics, defaultNic); - defaultNic = newDeviceInfo.first(); - deviceId = newDeviceInfo.second(); - } - createExtraNics(size, nics, nextNetwork); - if (nics.size() == 1) { - nics.get(0).setDefaultNic(true); - } - } - - /** - * private transaction method to check and add devices to the nic list and update the info - */ - Pair addRequestedNicToNicListWithDeviceNumberAndRetrieveDefaultDevice(NicProfile requested, boolean[] deviceIds, int deviceId, Network nextNetwork, List nics, NicProfile defaultNic) - throws InsufficientAddressCapacityException, InsufficientVirtualNetworkCapacityException { - Pair rc = new Pair<>(null, null); - Boolean isDefaultNic = false; - if (vm != null && requested != null && requested.isDefaultNic()) { - isDefaultNic = true; - } - - while (deviceIds[deviceId] && deviceId < deviceIds.length) { - deviceId++; - } - - final Pair vmNicPair = allocateNic(requested, nextNetwork, isDefaultNic, deviceId, vm); - NicProfile vmNic = null; - if (vmNicPair != null) { - vmNic = vmNicPair.first(); - if (vmNic == null) { - return rc; - } - deviceId = vmNicPair.second(); - } - - final int devId = vmNic.getDeviceId(); - if (devId >= deviceIds.length) { - throw new IllegalArgumentException("Device id for nic is too large: " + vmNic); - } - if (deviceIds[devId]) { - throw new IllegalArgumentException("Conflicting device id for two different nics: " + vmNic); - } - - deviceIds[devId] = true; - - if (vmNic.isDefaultNic()) { - if (defaultNic != null) { - throw new IllegalArgumentException("You cannot specify two nics as default nics: nic 1 = " + defaultNic + "; nic 2 = " + vmNic); - } - defaultNic = vmNic; - } - - nics.add(vmNic); - vm.addNic(vmNic); - saveExtraDhcpOptions(nextNetwork.getUuid(), vmNic.getId(), extraDhcpOptions); - rc.first(defaultNic); - rc.second(deviceId); - return rc; - } - - /** - * private transaction method to get oredered list of Network and NicProfile pair - * @return ordered list of Network and NicProfile pair - * @param networks the map od networks to nic profiles list - */ - private List> getOrderedNetworkNicProfileMapping(final LinkedHashMap> networks) { - List> profilesList = new ArrayList<>(); for (final Map.Entry> network : networks.entrySet()) { + final Network config = network.getKey(); List requestedProfiles = network.getValue(); if (requestedProfiles == null) { requestedProfiles = new ArrayList(); @@ -903,72 +780,57 @@ private List> getOrderedNetworkNicProfileMapping(final if (requestedProfiles.isEmpty()) { requestedProfiles.add(null); } + for (final NicProfile requested : requestedProfiles) { - profilesList.add(new Pair(network.getKey(), requested)); - } - } - profilesList.sort(new Comparator>() { - @Override - public int compare(Pair pair1, Pair pair2) { - int profile1Order = Integer.MAX_VALUE; - int profile2Order = Integer.MAX_VALUE; - if (pair1 != null && pair1.second() != null && pair1.second().getOrderIndex() != null) { - profile1Order = pair1.second().getOrderIndex(); + Boolean isDefaultNic = false; + if (vm != null && requested != null && requested.isDefaultNic()) { + isDefaultNic = true; } - if (pair2 != null && pair2.second() != null && pair2.second().getOrderIndex() != null) { - profile2Order = pair2.second().getOrderIndex(); + + while (deviceIds[deviceId] && deviceId < deviceIds.length) { + deviceId++; } - return profile1Order - profile2Order; - } - }); - return profilesList; - } - /** - * private transaction method to run over the objects and determine nic requirements - * @return the total numer of nics required - */ - private int determineNumberOfNicsRequired() { - int size = 0; - for (final Network ntwk : networks.keySet()) { - final List profiles = networks.get(ntwk); - if (profiles != null && !profiles.isEmpty()) { - size = size + profiles.size(); - } else { - size = size + 1; - } - } + final Pair vmNicPair = allocateNic(requested, config, isDefaultNic, deviceId, vm); + NicProfile vmNic = null; + if (vmNicPair != null) { + vmNic = vmNicPair.first(); + if (vmNic == null) { + continue; + } + deviceId = vmNicPair.second(); + } - List netprereqs = templateDeployAsIsDetailsDao.listNetworkRequirementsByTemplateId(vm.getTemplate().getId()); - if (size < netprereqs.size()) { - size = netprereqs.size(); - } - return size; - } - - /** - * private transaction method to add nics as required - * @param size the number needed - * @param nics the list of nics present - * @param finalNetwork the network to add the nics to - * @throws InsufficientVirtualNetworkCapacityException great - * @throws InsufficientAddressCapacityException also magnificent, as the name sugests - */ - private void createExtraNics(int size, List nics, Network finalNetwork) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { - if (nics.size() != size) { - s_logger.warn("Number of nics " + nics.size() + " doesn't match number of requested nics " + size); - if (nics.size() > size) { - throw new CloudRuntimeException("Number of nics " + nics.size() + " doesn't match number of requested networks " + size); - } else { - if (finalNetwork == null) { - throw new CloudRuntimeException(String.format("can not assign network to %d remaining required NICs", size - nics.size())); + final int devId = vmNic.getDeviceId(); + if (devId >= deviceIds.length) { + throw new IllegalArgumentException("Device id for nic is too large: " + vmNic); } - // create extra - for (int extraNicNum = nics.size(); extraNicNum < size; extraNicNum++) { - final Pair vmNicPair = allocateNic(new NicProfile(), finalNetwork, false, extraNicNum, vm); + if (deviceIds[devId]) { + throw new IllegalArgumentException("Conflicting device id for two different nics: " + vmNic); } + + deviceIds[devId] = true; + + if (vmNic.isDefaultNic()) { + if (defaultNic != null) { + throw new IllegalArgumentException("You cannot specify two nics as default nics: nic 1 = " + defaultNic + "; nic 2 = " + vmNic); + } + defaultNic = vmNic; + } + + nics.add(vmNic); + vm.addNic(vmNic); + saveExtraDhcpOptions(config.getUuid(), vmNic.getId(), extraDhcpOptions); } } + if (nics.size() != size) { + s_logger.warn("Number of nics " + nics.size() + " doesn't match number of requested nics " + size); + throw new CloudRuntimeException("Number of nics " + nics.size() + " doesn't match number of requested networks " + size); + } + + if (nics.size() == 1) { + nics.get(0).setDefaultNic(true); + } } }); } @@ -976,9 +838,9 @@ private void createExtraNics(int size, List nics, Network finalNetwo @Override public void saveExtraDhcpOptions(final String networkUuid, final Long nicId, final Map> extraDhcpOptionMap) { - if (extraDhcpOptionMap != null) { + if(extraDhcpOptionMap != null) { Map extraDhcpOption = extraDhcpOptionMap.get(networkUuid); - if (extraDhcpOption != null) { + if(extraDhcpOption != null) { List nicExtraDhcpOptionList = new LinkedList<>(); for (Integer code : extraDhcpOption.keySet()) { @@ -1084,7 +946,7 @@ protected void configureNicProfileBasedOnRequestedIp(NicProfile requestedNicProf } /** - * Acquires lock in "user_ip_address" and checks if the requested IPv4 address is Free. + * Acquires lock in "user_ip_address" and checks if the requested IPv4 address is Free. */ protected void acquireLockAndCheckIfIpv4IsFree(Network network, String requestedIpv4Address) { IPAddressVO ipVO = _ipAddressDao.findByIpAndSourceNetworkId(network.getId(), requestedIpv4Address); @@ -1213,12 +1075,11 @@ protected NicTO toNicTO(final NicVO nic, final NicProfile profile, final Network boolean isNetworkImplemented(final NetworkVO network) { final Network.State state = network.getState(); - final NetworkOfferingVO offeringVO = _networkOfferingDao.findById(network.getNetworkOfferingId()); if (state == Network.State.Implemented) { return true; } else if (state == Network.State.Setup) { final DataCenterVO zone = _dcDao.findById(network.getDataCenterId()); - if ((!isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) && !offeringVO.isPersistent()) || zone.getNetworkType() == NetworkType.Basic) { + if (!isSharedNetworkOfferingWithServices(network.getNetworkOfferingId()) || zone.getNetworkType() == NetworkType.Basic) { return true; } } @@ -1243,85 +1104,6 @@ Pair implementNetwork(final long networkId, final Deploy return implemented; } - /** - * Creates a dummy NicTO object which is used by the respective hypervisors to setup network elements / resources - * - bridges(KVM), VLANs(Xen) and portgroups(VMWare) for L2 network - */ - private NicTO createNicTOFromNetworkAndOffering(NetworkVO networkVO, NetworkOfferingVO networkOfferingVO, HostVO hostVO) { - NicTO to = new NicTO(); - to.setName(_networkModel.getNetworkTag(hostVO.getHypervisorType(), networkVO)); - to.setBroadcastType(networkVO.getBroadcastDomainType()); - to.setType(networkVO.getTrafficType()); - to.setBroadcastUri(networkVO.getBroadcastUri()); - to.setIsolationuri(networkVO.getBroadcastUri()); - to.setNetworkRateMbps(_configMgr.getNetworkOfferingNetworkRate(networkOfferingVO.getId(), networkVO.getDataCenterId())); - to.setSecurityGroupEnabled(_networkModel.isSecurityGroupSupportedInNetwork(networkVO)); - return to; - } - - private Pair isNtwConfiguredInCluster(HostVO hostVO, Map> clusterToHostsMap, NetworkVO networkVO, NetworkOfferingVO networkOfferingVO) { - Long clusterId = hostVO.getClusterId(); - List hosts = clusterToHostsMap.get(clusterId); - if (hosts == null) { - hosts = new ArrayList<>(); - } - if (hostVO.getHypervisorType() == HypervisorType.KVM || hostVO.getHypervisorType() == HypervisorType.XenServer) { - hosts.add(hostVO.getId()); - clusterToHostsMap.put(clusterId, hosts); - return new Pair<>(false, createNicTOFromNetworkAndOffering(networkVO, networkOfferingVO, hostVO)); - } - if (hosts != null && !hosts.isEmpty()) { - return new Pair<>(true, createNicTOFromNetworkAndOffering(networkVO, networkOfferingVO, hostVO)); - } - hosts.add(hostVO.getId()); - clusterToHostsMap.put(clusterId, hosts); - return new Pair<>(false, createNicTOFromNetworkAndOffering(networkVO, networkOfferingVO, hostVO)); - } - - private void setupPersistentNetwork(NetworkVO network, NetworkOfferingVO offering, Long dcId) throws AgentUnavailableException, OperationTimedoutException { - List clusterVOs = clusterDao.listClustersByDcId(dcId); - List hosts = resourceManager.listAllUpAndEnabledHostsInOneZoneByType(Host.Type.Routing, dcId); - Map> clusterToHostsMap = new HashMap<>(); - - for (HostVO host : hosts) { - try { - Pair networkCfgStateAndDetails = isNtwConfiguredInCluster(host, clusterToHostsMap, network, offering); - if (networkCfgStateAndDetails.first()) { - continue; - } - NicTO to = networkCfgStateAndDetails.second(); - SetupPersistentNetworkCommand cmd = new SetupPersistentNetworkCommand(to); - final SetupPersistentNetworkAnswer answer = (SetupPersistentNetworkAnswer) _agentMgr.send(host.getId(), cmd); - - if (answer == null) { - s_logger.warn("Unable to get an answer to the SetupPersistentNetworkCommand from agent:" + host.getId()); - clusterToHostsMap.get(host.getClusterId()).remove(host.getId()); - continue; - } - - if (!answer.getResult()) { - s_logger.warn("Unable to setup agent " + host.getId() + " due to " + answer.getDetails()); - clusterToHostsMap.get(host.getClusterId()).remove(host.getId()); - } - } catch (Exception e) { - s_logger.warn("Failed to connect to host: " + host.getName()); - } - } - if (clusterToHostsMap.keySet().size() != clusterVOs.size()) { - s_logger.warn("Hosts on all clusters may not have been configured with network devices."); - } - } - - private boolean networkMeetsPersistenceCriteria(NetworkVO network, NetworkOfferingVO offering, boolean cleanup) { - boolean criteriaMet = offering.isPersistent() && - (network.getBroadcastUri() != null && BroadcastDomainType.getSchemeValue(network.getBroadcastUri()) == BroadcastDomainType.Vlan); - if (!cleanup) { - return criteriaMet && network.getGuestType() == GuestType.L2; - } else { - return criteriaMet && (network.getGuestType() == GuestType.L2 || network.getGuestType() == GuestType.Isolated); - } - } - @Override @DB public Pair implementNetwork(final long networkId, final DeployDestination dest, final ReservationContext context) throws ConcurrentOperationException, @@ -1380,10 +1162,6 @@ public Pair implementNetwork(final long networkId, final // implement network elements and re-apply all the network rules implementNetworkElementsAndResources(dest, context, network, offering); - long dcId = dest.getDataCenter().getId(); - if (networkMeetsPersistenceCriteria(network, offering, false)) { - setupPersistentNetwork(network, offering, dcId); - } if (isSharedNetworkWithServices(network)) { network.setState(Network.State.Implemented); } else { @@ -1396,10 +1174,10 @@ public Pair implementNetwork(final long networkId, final return implemented; } catch (final NoTransitionException e) { s_logger.error(e.getMessage()); - return new Pair(null, null); - } catch (final CloudRuntimeException | OperationTimedoutException e) { + return null; + } catch (final CloudRuntimeException e) { s_logger.error("Caught exception: " + e.getMessage()); - return new Pair(null, null); + return null; } finally { if (implemented.first() == null) { s_logger.debug("Cleaning up because we're unable to implement the network " + network); @@ -1467,15 +1245,15 @@ public void implementNetworkElementsAndResources(final DeployDestination dest, f //Reset the extra DHCP option that may have been cleared per nic. List nicVOs = _nicDao.listByNetworkId(network.getId()); - for (NicVO nicVO : nicVOs) { - if (nicVO.getState() == Nic.State.Reserved) { + for(NicVO nicVO : nicVOs) { + if(nicVO.getState() == Nic.State.Reserved) { configureExtraDhcpOptions(network, nicVO.getId()); } } for (final NetworkElement element : networkElements) { if (element instanceof AggregatedCommandExecutor && providersToImplement.contains(element.getProvider())) { - ((AggregatedCommandExecutor) element).prepareAggregatedExecution(network, dest); + ((AggregatedCommandExecutor)element).prepareAggregatedExecution(network, dest); } } @@ -1492,7 +1270,7 @@ public void implementNetworkElementsAndResources(final DeployDestination dest, f } for (final NetworkElement element : networkElements) { if (element instanceof AggregatedCommandExecutor && providersToImplement.contains(element.getProvider())) { - if (!((AggregatedCommandExecutor) element).completeAggregatedExecution(network, dest)) { + if (!((AggregatedCommandExecutor)element).completeAggregatedExecution(network, dest)) { s_logger.warn("Failed to re-program the network as a part of network " + network + " implement due to aggregated commands execution failure!"); // see DataCenterVO.java final ResourceUnavailableException ex = new ResourceUnavailableException("Unable to apply network rules as a part of network " + network + " implement", DataCenter.class, @@ -1505,7 +1283,7 @@ public void implementNetworkElementsAndResources(final DeployDestination dest, f } finally { for (final NetworkElement element : networkElements) { if (element instanceof AggregatedCommandExecutor && providersToImplement.contains(element.getProvider())) { - ((AggregatedCommandExecutor) element).cleanupAggregatedExecution(network, dest); + ((AggregatedCommandExecutor)element).cleanupAggregatedExecution(network, dest); } } } @@ -1625,32 +1403,32 @@ protected boolean prepareElement(final NetworkElement element, final Network net if (vmProfile.getType() == Type.User && element.getProvider() != null) { if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dhcp) && _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dhcp, element.getProvider()) && element instanceof DhcpServiceProvider) { - final DhcpServiceProvider sp = (DhcpServiceProvider) element; + final DhcpServiceProvider sp = (DhcpServiceProvider)element; if (isDhcpAccrossMultipleSubnetsSupported(sp)) { if (!sp.configDhcpSupportForSubnet(network, profile, vmProfile, dest, context)) { return false; } } - if (!sp.addDhcpEntry(network, profile, vmProfile, dest, context)) { + if(!sp.addDhcpEntry(network, profile, vmProfile, dest, context)) { return false; } } if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dns) && _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.Dns, element.getProvider()) && element instanceof DnsServiceProvider) { - final DnsServiceProvider sp = (DnsServiceProvider) element; + final DnsServiceProvider sp = (DnsServiceProvider)element; if (profile.getIPv6Address() == null) { if (!sp.configDnsSupportForSubnet(network, profile, vmProfile, dest, context)) { return false; } } - if (!sp.addDnsEntry(network, profile, vmProfile, dest, context)) { + if(!sp.addDnsEntry(network, profile, vmProfile, dest, context)) { return false; } } if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.UserData) && _networkModel.isProviderSupportServiceInNetwork(network.getId(), Service.UserData, element.getProvider()) && element instanceof UserDataServiceProvider) { - final UserDataServiceProvider sp = (UserDataServiceProvider) element; - if (!sp.addPasswordAndUserdata(network, profile, vmProfile, dest, context)) { + final UserDataServiceProvider sp = (UserDataServiceProvider)element; + if(!sp.addPasswordAndUserdata(network, profile, vmProfile, dest, context)){ return false; } } @@ -1659,20 +1437,20 @@ protected boolean prepareElement(final NetworkElement element, final Network net } @Override - public boolean canUpdateInSequence(Network network, boolean forced) { + public boolean canUpdateInSequence(Network network, boolean forced){ List providers = getNetworkProviders(network.getId()); //check if the there are no service provider other than virtualrouter. - for (Provider provider : providers) { + for(Provider provider : providers) { if (provider != Provider.VirtualRouter) throw new UnsupportedOperationException("Cannot update the network resources in sequence when providers other than virtualrouter are used"); } //check if routers are in correct state before proceeding with the update - List routers = routerDao.listByNetworkAndRole(network.getId(), VirtualRouter.Role.VIRTUAL_ROUTER); + List routers = _routerDao.listByNetworkAndRole(network.getId(), VirtualRouter.Role.VIRTUAL_ROUTER); for (DomainRouterVO router : routers){ if (router.getRedundantState() == VirtualRouter.RedundantState.UNKNOWN) { if (!forced) { - throw new CloudRuntimeException("Domain router: " + router.getInstanceName() + " is in unknown state, Cannot update network. set parameter forced to true for forcing an update"); + throw new CloudRuntimeException("Domain router: "+router.getInstanceName()+" is in unknown state, Cannot update network. set parameter forced to true for forcing an update"); } } } @@ -1680,23 +1458,23 @@ public boolean canUpdateInSequence(Network network, boolean forced) { } @Override - public List getServicesNotSupportedInNewOffering(Network network, long newNetworkOfferingId) { - NetworkOffering offering = _networkOfferingDao.findById(newNetworkOfferingId); - List services = _ntwkOfferingSrvcDao.listServicesForNetworkOffering(offering.getId()); - List serviceMap = _ntwkSrvcDao.getServicesInNetwork(network.getId()); - List servicesNotInNewOffering = new ArrayList<>(); - for (NetworkServiceMapVO serviceVO : serviceMap) { - boolean inlist = false; - for (String service : services) { - if (serviceVO.getService().equalsIgnoreCase(service)) { - inlist = true; + public List getServicesNotSupportedInNewOffering(Network network,long newNetworkOfferingId){ + NetworkOffering offering =_networkOfferingDao.findById(newNetworkOfferingId); + List services=_ntwkOfferingSrvcDao.listServicesForNetworkOffering(offering.getId()); + List serviceMap= _ntwkSrvcDao.getServicesInNetwork(network.getId()); + List servicesNotInNewOffering=new ArrayList<>(); + for(NetworkServiceMapVO serviceVO :serviceMap){ + boolean inlist=false; + for(String service: services){ + if(serviceVO.getService().equalsIgnoreCase(service)){ + inlist=true; break; } } - if (!inlist) { + if(!inlist){ //ignore Gateway service as this has no effect on the //behaviour of network. - if (!serviceVO.getService().equalsIgnoreCase(Service.Gateway.getName())) + if(!serviceVO.getService().equalsIgnoreCase(Service.Gateway.getName())) servicesNotInNewOffering.add(serviceVO.getService()); } } @@ -1704,21 +1482,21 @@ public List getServicesNotSupportedInNewOffering(Network network, long n } @Override - public void cleanupConfigForServicesInNetwork(List services, final Network network) { - long networkId = network.getId(); - Account caller = _accountDao.findById(Account.ACCOUNT_ID_SYSTEM); - long userId = User.UID_SYSTEM; + public void cleanupConfigForServicesInNetwork(List services, final Network network){ + long networkId=network.getId(); + Account caller=_accountDao.findById(Account.ACCOUNT_ID_SYSTEM); + long userId=User.UID_SYSTEM; //remove all PF/Static Nat rules for the network - s_logger.info("Services:" + services + " are no longer supported in network:" + network.getUuid() + - " after applying new network offering:" + network.getNetworkOfferingId() + " removing the related configuration"); - if (services.contains(Service.StaticNat.getName()) || services.contains(Service.PortForwarding.getName())) { + s_logger.info("Services:"+services+" are no longer supported in network:"+network.getUuid()+ + " after applying new network offering:"+network.getNetworkOfferingId()+" removing the related configuration"); + if(services.contains(Service.StaticNat.getName())|| services.contains(Service.PortForwarding.getName())) { try { if (_rulesMgr.revokeAllPFStaticNatRulesForNetwork(networkId, userId, caller)) { s_logger.debug("Successfully cleaned up portForwarding/staticNat rules for network id=" + networkId); } else { s_logger.warn("Failed to release portForwarding/StaticNat rules as a part of network id=" + networkId + " cleanup"); } - if (services.contains(Service.StaticNat.getName())) { + if(services.contains(Service.StaticNat.getName())){ //removing static nat configured on ips. //optimizing the db operations using transaction. Transaction.execute(new TransactionCallbackNoReturn() { @@ -1729,7 +1507,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) { ip.setOneToOneNat(false); ip.setAssociatedWithVmId(null); ip.setVmIp(null); - _ipAddressDao.update(ip.getId(), ip); + _ipAddressDao.update(ip.getId(),ip); } } }); @@ -1738,20 +1516,20 @@ public void doInTransactionWithoutResult(TransactionStatus status) { s_logger.warn("Failed to release portForwarding/StaticNat rules as a part of network id=" + networkId + " cleanup due to resourceUnavailable ", ex); } } - if (services.contains(Service.SourceNat.getName())) { + if(services.contains(Service.SourceNat.getName())){ Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(TransactionStatus status) { - List ips = _ipAddressDao.listByAssociatedNetwork(network.getId(), true); + List ips = _ipAddressDao.listByAssociatedNetwork(network.getId(),true); //removing static nat configured on ips. for (IPAddressVO ip : ips) { ip.setSourceNat(false); - _ipAddressDao.update(ip.getId(), ip); + _ipAddressDao.update(ip.getId(),ip); } } }); } - if (services.contains(Service.Lb.getName())) { + if(services.contains(Service.Lb.getName())){ //remove all LB rules for the network if (_lbMgr.removeAllLoadBalanacersForNetwork(networkId, caller, userId)) { s_logger.debug("Successfully cleaned up load balancing rules for network id=" + networkId); @@ -1760,7 +1538,7 @@ public void doInTransactionWithoutResult(TransactionStatus status) { } } - if (services.contains(Service.Firewall.getName())) { + if(services.contains(Service.Firewall.getName())){ //revoke all firewall rules for the network try { if (_firewallMgr.revokeAllFirewallRulesForNetwork(networkId, userId, caller)) { @@ -1774,12 +1552,12 @@ public void doInTransactionWithoutResult(TransactionStatus status) { } //do not remove vpn service for vpc networks. - if (services.contains(Service.Vpn.getName()) && network.getVpcId() == null) { - RemoteAccessVpnVO vpn = _remoteAccessVpnDao.findByAccountAndNetwork(network.getAccountId(), networkId); + if(services.contains(Service.Vpn.getName()) && network.getVpcId()==null){ + RemoteAccessVpnVO vpn = _remoteAccessVpnDao.findByAccountAndNetwork(network.getAccountId(),networkId); try { _vpnMgr.destroyRemoteAccessVpnForIp(vpn.getServerAddressId(), caller, true); } catch (ResourceUnavailableException ex) { - s_logger.warn("Failed to cleanup remote access vpn resources of network:" + network.getUuid() + " due to Exception: ", ex); + s_logger.warn("Failed to cleanup remote access vpn resources of network:"+network.getUuid() + " due to Exception: ", ex); } } } @@ -1797,14 +1575,14 @@ public void configureUpdateInSequence(Network network) { } @Override - public int getResourceCount(Network network) { + public int getResourceCount(Network network){ List providers = getNetworkProviders(network.getId()); - int resourceCount = 0; + int resourceCount=0; for (NetworkElement element : networkElements) { if (providers.contains(element.getProvider())) { //currently only one element implements the redundant resource interface if (element instanceof RedundantResource) { - resourceCount = ((RedundantResource) element).getResourceCount(network); + resourceCount= ((RedundantResource) element).getResourceCount(network); break; } } @@ -1814,7 +1592,7 @@ public int getResourceCount(Network network) { @Override public void configureExtraDhcpOptions(Network network, long nicId, Map extraDhcpOptions) { - if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dhcp)) { + if(_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dhcp)) { if (_networkModel.getNetworkServiceCapabilities(network.getId(), Service.Dhcp).containsKey(Capability.ExtraDhcpOptions)) { DhcpServiceProvider sp = getDhcpServiceProvider(network); sp.setExtraDhcpOptions(network, nicId, extraDhcpOptions); @@ -1835,7 +1613,7 @@ public void finalizeUpdateInSequence(Network network, boolean success) { if (providers.contains(element.getProvider())) { //currently only one element implements the redundant resource interface if (element instanceof RedundantResource) { - ((RedundantResource) element).finalize(network, success); + ((RedundantResource) element).finalize(network,success); break; } } @@ -1984,7 +1762,14 @@ public NicProfile prepareNic(final VirtualMachineProfile vmProfile, final Deploy profile.setSecurityGroupEnabled(_networkModel.isSecurityGroupSupportedInNetwork(network)); guru.updateNicProfile(profile, network); - updateRouterDefaultDns(vmProfile, profile); + + if(guru instanceof NetworkGuruTungsten){ + String tungstenVirtualMachineUuid = ((NetworkGuruTungsten) guru).createVirtualMachineInTungsten(vmProfile.getUuid(), vmProfile.getInstanceName()); + String tungstenVmInterfaceUuid = ((NetworkGuruTungsten) guru).createVmInterfaceInTungsten(vmProfile.getInstanceName(), "2853b16f-176e-4c7d-8931-423e496fad38", + network.getTungstenNetworkUuid(), tungstenVirtualMachineUuid, null, Arrays.asList(nic.getMacAddress())); + ((NetworkGuruTungsten) guru).createTungstenInstanceIp("TungstenInstanceTest", tungstenVmInterfaceUuid, network.getTungstenNetworkUuid(), nic.getIPv4Address()); + } + configureExtraDhcpOptions(network, nicId); return profile; } @@ -1999,7 +1784,7 @@ public Map getExtraDhcpOptions(long nicId) { @Override public void prepareNicForMigration(final VirtualMachineProfile vm, final DeployDestination dest) { - if (vm.getType().equals(VirtualMachine.Type.DomainRouter) && (vm.getHypervisorType().equals(HypervisorType.KVM) || vm.getHypervisorType().equals(HypervisorType.VMware))) { + if(vm.getType().equals(VirtualMachine.Type.DomainRouter) && (vm.getHypervisorType().equals(HypervisorType.KVM) || vm.getHypervisorType().equals(HypervisorType.VMware))) { //Include nics hot plugged and not stored in DB prepareAllNicsForMigration(vm, dest); return; @@ -2014,15 +1799,10 @@ public void prepareNicForMigration(final VirtualMachineProfile vm, final DeployD final NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vm.getHypervisorType(), network)); if (guru instanceof NetworkMigrationResponder) { - if (!((NetworkMigrationResponder) guru).prepareMigration(profile, network, vm, dest, context)) { + if (!((NetworkMigrationResponder)guru).prepareMigration(profile, network, vm, dest, context)) { s_logger.error("NetworkGuru " + guru + " prepareForMigration failed."); // XXX: Transaction error } } - - if (network.getGuestType() == Network.GuestType.L2 && vm.getType() == VirtualMachine.Type.User) { - _userVmMgr.setupVmForPvlan(false, vm.getVirtualMachine().getHostId(), profile); - } - final List providersToImplement = getNetworkProviders(network.getId()); for (final NetworkElement element : networkElements) { if (providersToImplement.contains(element.getProvider())) { @@ -2031,7 +1811,7 @@ public void prepareNicForMigration(final VirtualMachineProfile vm, final DeployD + network.getPhysicalNetworkId()); } if (element instanceof NetworkMigrationResponder) { - if (!((NetworkMigrationResponder) element).prepareMigration(profile, network, vm, dest, context)) { + if (!((NetworkMigrationResponder)element).prepareMigration(profile, network, vm, dest, context)) { s_logger.error("NetworkElement " + element + " prepareForMigration failed."); // XXX: Transaction error } } @@ -2054,7 +1834,7 @@ public void prepareAllNicsForMigration(final VirtualMachineProfile vm, final Dep Long guestNetworkId = null; for (final NicVO nic : nics) { final NetworkVO network = _networksDao.findById(nic.getNetworkId()); - if (network.getTrafficType().equals(TrafficType.Guest) && network.getGuestType().equals(GuestType.Isolated)) { + if(network.getTrafficType().equals(TrafficType.Guest) && network.getGuestType().equals(GuestType.Isolated)){ guestNetworkId = network.getId(); } final Integer networkRate = _networkModel.getNetworkRate(network.getId(), vm.getId()); @@ -2062,9 +1842,9 @@ public void prepareAllNicsForMigration(final VirtualMachineProfile vm, final Dep final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, network.getGuruName()); final NicProfile profile = new NicProfile(nic, network, nic.getBroadcastUri(), nic.getIsolationUri(), networkRate, _networkModel.isSecurityGroupSupportedInNetwork(network), _networkModel.getNetworkTag(vm.getHypervisorType(), network)); - if (guru instanceof NetworkMigrationResponder) { - if (!((NetworkMigrationResponder) guru).prepareMigration(profile, network, vm, dest, context)) { - s_logger.error("NetworkGuru " + guru + " prepareForMigration failed."); // XXX: Transaction error + if(guru instanceof NetworkMigrationResponder){ + if(!((NetworkMigrationResponder) guru).prepareMigration(profile, network, vm, dest, context)){ + s_logger.error("NetworkGuru "+guru+" prepareForMigration failed."); // XXX: Transaction error } } final List providersToImplement = getNetworkProviders(network.getId()); @@ -2073,9 +1853,9 @@ public void prepareAllNicsForMigration(final VirtualMachineProfile vm, final Dep if (!_networkModel.isProviderEnabledInPhysicalNetwork(_networkModel.getPhysicalNetworkId(network), element.getProvider().getName())) { throw new CloudRuntimeException("Service provider " + element.getProvider().getName() + " either doesn't exist or is not enabled in physical network id: " + network.getPhysicalNetworkId()); } - if (element instanceof NetworkMigrationResponder) { - if (!((NetworkMigrationResponder) element).prepareMigration(profile, network, vm, dest, context)) { - s_logger.error("NetworkElement " + element + " prepareForMigration failed."); // XXX: Transaction error + if(element instanceof NetworkMigrationResponder){ + if(!((NetworkMigrationResponder) element).prepareMigration(profile, network, vm, dest, context)){ + s_logger.error("NetworkElement "+element+" prepareForMigration failed."); // XXX: Transaction error } } } @@ -2085,19 +1865,20 @@ public void prepareAllNicsForMigration(final VirtualMachineProfile vm, final Dep } final List addedURIs = new ArrayList(); - if (guestNetworkId != null) { + if(guestNetworkId != null){ final List publicIps = _ipAddressDao.listByAssociatedNetwork(guestNetworkId, null); - for (final IPAddressVO userIp : publicIps) { + for (final IPAddressVO userIp : publicIps){ final PublicIp publicIp = PublicIp.createFromAddrAndVlan(userIp, _vlanDao.findById(userIp.getVlanId())); final URI broadcastUri = BroadcastDomainType.Vlan.toUri(publicIp.getVlanTag()); final long ntwkId = publicIp.getNetworkId(); final Nic nic = _nicDao.findByNetworkIdInstanceIdAndBroadcastUri(ntwkId, vm.getId(), broadcastUri.toString()); - if (nic == null && !addedURIs.contains(broadcastUri.toString())) { + if(nic == null && !addedURIs.contains(broadcastUri.toString())){ //Nic details are not available in DB //Create nic profile for migration - s_logger.debug("Creating nic profile for migration. BroadcastUri: " + broadcastUri.toString() + " NetworkId: " + ntwkId + " Vm: " + vm.getId()); + s_logger.debug("Creating nic profile for migration. BroadcastUri: "+broadcastUri.toString()+" NetworkId: "+ntwkId+" Vm: "+vm.getId()); final NetworkVO network = _networksDao.findById(ntwkId); + _networkModel.getNetworkRate(network.getId(), vm.getId()); final NetworkGuru guru = AdapterBase.getAdapterByName(networkGurus, network.getGuruName()); final NicProfile profile = new NicProfile(); profile.setDeviceId(255); //dummyId @@ -2111,8 +1892,7 @@ public void prepareAllNicsForMigration(final VirtualMachineProfile vm, final Dep profile.setIsolationUri(Networks.IsolationType.Vlan.toUri(publicIp.getVlanTag())); profile.setSecurityGroupEnabled(_networkModel.isSecurityGroupSupportedInNetwork(network)); profile.setName(_networkModel.getNetworkTag(vm.getHypervisorType(), network)); - profile.setNetworkRate(_networkModel.getNetworkRate(network.getId(), vm.getId())); - profile.setNetworkId(network.getId()); + profile.setNetworId(network.getId()); guru.updateNicProfile(profile, network); vm.addNic(profile); @@ -2141,13 +1921,8 @@ public void commitNicForMigration(final VirtualMachineProfile src, final Virtual final ReservationContext dst_context = new ReservationContextImpl(nicDst.getReservationId(), null, null); if (guru instanceof NetworkMigrationResponder) { - ((NetworkMigrationResponder) guru).commitMigration(nicSrc, network, src, src_context, dst_context); - } - - if (network.getGuestType() == Network.GuestType.L2 && src.getType() == VirtualMachine.Type.User) { - _userVmMgr.setupVmForPvlan(true, src.getVirtualMachine().getHostId(), nicSrc); + ((NetworkMigrationResponder)guru).commitMigration(nicSrc, network, src, src_context, dst_context); } - final List providersToImplement = getNetworkProviders(network.getId()); for (final NetworkElement element : networkElements) { if (providersToImplement.contains(element.getProvider())) { @@ -2156,7 +1931,7 @@ public void commitNicForMigration(final VirtualMachineProfile src, final Virtual + network.getPhysicalNetworkId()); } if (element instanceof NetworkMigrationResponder) { - ((NetworkMigrationResponder) element).commitMigration(nicSrc, network, src, src_context, dst_context); + ((NetworkMigrationResponder)element).commitMigration(nicSrc, network, src, src_context, dst_context); } } } @@ -2177,13 +1952,8 @@ public void rollbackNicForMigration(final VirtualMachineProfile src, final Virtu final ReservationContext dst_context = new ReservationContextImpl(nicDst.getReservationId(), null, null); if (guru instanceof NetworkMigrationResponder) { - ((NetworkMigrationResponder) guru).rollbackMigration(nicDst, network, dst, src_context, dst_context); + ((NetworkMigrationResponder)guru).rollbackMigration(nicDst, network, dst, src_context, dst_context); } - - if (network.getGuestType() == Network.GuestType.L2 && src.getType() == VirtualMachine.Type.User) { - _userVmMgr.setupVmForPvlan(true, dst.getVirtualMachine().getHostId(), nicDst); - } - final List providersToImplement = getNetworkProviders(network.getId()); for (final NetworkElement element : networkElements) { if (providersToImplement.contains(element.getProvider())) { @@ -2192,7 +1962,7 @@ public void rollbackNicForMigration(final VirtualMachineProfile src, final Virtu + network.getPhysicalNetworkId()); } if (element instanceof NetworkMigrationResponder) { - ((NetworkMigrationResponder) element).rollbackMigration(nicDst, network, dst, src_context, dst_context); + ((NetworkMigrationResponder)element).rollbackMigration(nicDst, network, dst, src_context, dst_context); } } } @@ -2256,12 +2026,12 @@ public Pair doInTransaction(final TransactionStatus status) }); // cleanup the entry in vm_network_map - if (vmProfile.getType().equals(VirtualMachine.Type.User)) { + if(vmProfile.getType().equals(VirtualMachine.Type.User)) { final NicVO nic = _nicDao.findById(nicId); - if (nic != null) { + if(nic != null) { final NetworkVO vmNetwork = _networksDao.findById(nic.getNetworkId()); final VMNetworkMapVO vno = _vmNetworkMapDao.findByVmAndNetworkId(vmProfile.getVirtualMachine().getId(), vmNetwork.getId()); - if (vno != null) { + if(vno != null) { _vmNetworkMapDao.remove(vno.getId()); } } @@ -2315,8 +2085,8 @@ protected void removeNic(final VirtualMachineProfile vm, final NicVO nic) { final NetworkVO network = _networksDao.findById(nic.getNetworkId()); if (network != null && network.getTrafficType() == TrafficType.Guest) { - final String nicIp = StringUtils.isEmpty(nic.getIPv4Address()) ? nic.getIPv6Address() : nic.getIPv4Address(); - if (StringUtils.isNotEmpty(nicIp)) { + final String nicIp = Strings.isNullOrEmpty(nic.getIPv4Address()) ? nic.getIPv6Address() : nic.getIPv4Address(); + if (!Strings.isNullOrEmpty(nicIp)) { NicProfile nicProfile = new NicProfile(nic.getIPv4Address(), nic.getIPv6Address(), nic.getMacAddress()); nicProfile.setId(nic.getId()); cleanupNicDhcpDnsEntry(network, vm, nicProfile); @@ -2366,11 +2136,11 @@ && isDhcpAccrossMultipleSubnetsSupported(dhcpServiceProvider)) { removeDhcpServiceInSubnet(nic); } } - if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dns)) { + if (_networkModel.areServicesSupportedInNetwork(network.getId(), Service.Dns)){ final DnsServiceProvider dnsServiceProvider = getDnsServiceProvider(network); if (dnsServiceProvider != null) { try { - if (!dnsServiceProvider.removeDnsSupportForSubnet(network)) { + if(!dnsServiceProvider.removeDnsSupportForSubnet(network)) { s_logger.warn("Failed to remove the ip alias on the dns server"); } } catch (final ResourceUnavailableException e) { @@ -2388,16 +2158,6 @@ && isDhcpAccrossMultipleSubnetsSupported(dhcpServiceProvider)) { } s_logger.debug("Removed nic id=" + nic.getId()); - // release assigned IPv6 for Isolated Network VR NIC - - if (Type.User.equals(vm.getType()) && GuestType.Isolated.equals(network.getGuestType()) - && _networkOfferingDao.isIpv6Supported(network.getNetworkOfferingId()) && StringUtils.isNotEmpty(nic.getIPv6Address())) { - final boolean usageHidden = networkDetailsDao.isNetworkUsageHidden(network.getId()); - UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP6_RELEASE, network.getAccountId(), network.getDataCenterId(), 0L, - nic.getIPv6Address(), false, Vlan.VlanType.VirtualNetwork.toString(), false, usageHidden, - IPv6Address.class.getName(), null); - } - //remove the secondary ip addresses corresponding to to this nic if (!removeVmSecondaryIpsOfNic(nic.getId())) { s_logger.debug("Removing nic " + nic.getId() + " secondary ip addreses failed"); @@ -2450,10 +2210,10 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { } @Override - public void removeNics(final VirtualMachineProfile vm) { - final List nics = _nicDao.listByVmId(vm.getId()); + public void expungeNics(final VirtualMachineProfile vm) { + final List nics = _nicDao.listByVmIdIncludingRemoved(vm.getId()); for (final NicVO nic : nics) { - _nicDao.remove(nic.getId()); + _nicDao.expunge(nic.getId()); } } @@ -2463,8 +2223,7 @@ public Network createPrivateNetwork(final long networkOfferingId, final String n // create network for private gateway return createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, bypassVlanOverlapCheck, null, owner, null, pNtwk, pNtwk.getDataCenterId(), ACLType.Account, null, - vpcId, null, null, true, null, null, null, true, null, null, - null, null, null, null); + vpcId, null, null, true, null, null, null, true); } @Override @@ -2472,21 +2231,18 @@ public Network createPrivateNetwork(final long networkOfferingId, final String n public Network createGuestNetwork(final long networkOfferingId, final String name, final String displayText, final String gateway, final String cidr, String vlanId, boolean bypassVlanOverlapCheck, String networkDomain, final Account owner, final Long domainId, final PhysicalNetwork pNtwk, final long zoneId, final ACLType aclType, Boolean subdomainAccess, final Long vpcId, final String ip6Gateway, final String ip6Cidr, - final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId, - String routerIp, String routerIpv6, String ip4Dns1, String ip4Dns2, String ip6Dns1, String ip6Dns2) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { + final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { // create Isolated/Shared/L2 network return createGuestNetwork(networkOfferingId, name, displayText, gateway, cidr, vlanId, bypassVlanOverlapCheck, networkDomain, owner, domainId, pNtwk, zoneId, aclType, subdomainAccess, vpcId, ip6Gateway, ip6Cidr, - isDisplayNetworkEnabled, isolatedPvlan, isolatedPvlanType, externalId, false, routerIp, routerIpv6, ip4Dns1, ip4Dns2, ip6Dns1, ip6Dns2); + isDisplayNetworkEnabled, isolatedPvlan, isolatedPvlanType, externalId, false); } @DB private Network createGuestNetwork(final long networkOfferingId, final String name, final String displayText, final String gateway, final String cidr, String vlanId, boolean bypassVlanOverlapCheck, String networkDomain, final Account owner, final Long domainId, final PhysicalNetwork pNtwk, final long zoneId, final ACLType aclType, Boolean subdomainAccess, final Long vpcId, final String ip6Gateway, final String ip6Cidr, - final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId, - final Boolean isPrivateNetwork, String routerIp, String routerIpv6, final String ip4Dns1, final String ip4Dns2, - final String ip6Dns1, final String ip6Dns2) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { + final Boolean isDisplayNetworkEnabled, final String isolatedPvlan, Network.PVlanType isolatedPvlanType, String externalId, final Boolean isPrivateNetwork) throws ConcurrentOperationException, InsufficientCapacityException, ResourceAllocationException { final NetworkOfferingVO ntwkOff = _networkOfferingDao.findById(networkOfferingId); final DataCenterVO zone = _dcDao.findById(zoneId); @@ -2505,7 +2261,7 @@ private Network createGuestNetwork(final long networkOfferingId, final String na // Validate network offering if (ntwkOff.getState() != NetworkOffering.State.Enabled) { // see NetworkOfferingVO - final InvalidParameterValueException ex = new InvalidParameterValueException("Can't use specified network offering id as its state is not " + NetworkOffering.State.Enabled); + final InvalidParameterValueException ex = new InvalidParameterValueException("Can't use specified network offering id as its stat is not " + NetworkOffering.State.Enabled); ex.addProxyObject(ntwkOff.getUuid(), "networkOfferingId"); throw ex; } @@ -2520,7 +2276,7 @@ private Network createGuestNetwork(final long networkOfferingId, final String na boolean ipv6 = false; - if (StringUtils.isNoneBlank(ip6Gateway, ip6Cidr)) { + if (StringUtils.isNotBlank(ip6Gateway) && StringUtils.isNotBlank(ip6Cidr)) { ipv6 = true; } // Validate zone @@ -2590,30 +2346,24 @@ private Network createGuestNetwork(final long networkOfferingId, final String na final boolean vlanSpecified = vlanId != null; if (vlanSpecified != ntwkOff.isSpecifyVlan()) { if (vlanSpecified) { - if (!isSharedNetworkWithoutSpecifyVlan(ntwkOff) && !isPrivateGatewayWithoutSpecifyVlan(ntwkOff)) { - throw new InvalidParameterValueException("Can't specify vlan; corresponding offering says specifyVlan=false"); - } + throw new InvalidParameterValueException("Can't specify vlan; corresponding offering says specifyVlan=false"); } else { throw new InvalidParameterValueException("Vlan has to be specified; corresponding offering says specifyVlan=true"); } } if (vlanSpecified) { - URI uri = encodeVlanIdIntoBroadcastUri(vlanId, pNtwk); + URI uri = BroadcastDomainType.fromString(vlanId); // Aux: generate secondary URI for secondary VLAN ID (if provided) for performing checks - URI secondaryUri = StringUtils.isNotBlank(isolatedPvlan) ? BroadcastDomainType.fromString(isolatedPvlan) : null; - if (isSharedNetworkWithoutSpecifyVlan(ntwkOff) || isPrivateGatewayWithoutSpecifyVlan(ntwkOff)) { - bypassVlanOverlapCheck = true; - } + URI secondaryUri = isNotBlank(isolatedPvlan) ? BroadcastDomainType.fromString(isolatedPvlan) : null; //don't allow to specify vlan tag used by physical network for dynamic vlan allocation - if (!(bypassVlanOverlapCheck && (ntwkOff.getGuestType() == GuestType.Shared || isPrivateNetwork)) - && _dcDao.findVnet(zoneId, pNtwk.getId(), BroadcastDomainType.getValue(uri)).size() > 0) { - throw new InvalidParameterValueException("The VLAN tag to use for new guest network, " + vlanId + " is already being used for dynamic vlan allocation for the guest network in zone " + if (!(bypassVlanOverlapCheck && ntwkOff.getGuestType() == GuestType.Shared) && _dcDao.findVnet(zoneId, pNtwk.getId(), BroadcastDomainType.getValue(uri)).size() > 0) { + throw new InvalidParameterValueException("The VLAN tag " + vlanId + " is already being used for dynamic vlan allocation for the guest network in zone " + zone.getName()); } if (secondaryUri != null && !(bypassVlanOverlapCheck && ntwkOff.getGuestType() == GuestType.Shared) && _dcDao.findVnet(zoneId, pNtwk.getId(), BroadcastDomainType.getValue(secondaryUri)).size() > 0) { - throw new InvalidParameterValueException("The VLAN tag for isolated PVLAN " + isolatedPvlan + " is already being used for dynamic vlan allocation for the guest network in zone " + throw new InvalidParameterValueException("The VLAN tag " + isolatedPvlan + " is already being used for dynamic vlan allocation for the guest network in zone " + zone.getName()); } if (!UuidUtils.isUuid(vlanId)) { @@ -2653,7 +2403,7 @@ private Network createGuestNetwork(final long networkOfferingId, final String na } else { // don't allow to creating shared network with given Vlan ID, if there already exists a isolated network or // shared network with same Vlan ID in the zone - if (!bypassVlanOverlapCheck && _networksDao.listByZoneAndUriAndGuestType(zoneId, uri.toString(), GuestType.Isolated).size() > 0) { + if (!bypassVlanOverlapCheck && _networksDao.listByZoneAndUriAndGuestType(zoneId, uri.toString(), GuestType.Isolated).size() > 0 ) { throw new InvalidParameterValueException("There is an existing isolated/shared network that overlaps with vlan id:" + vlanId + " in zone " + zoneId); } } @@ -2704,11 +2454,8 @@ private Network createGuestNetwork(final long networkOfferingId, final String na && (ntwkOff.getGuestType() == GuestType.Shared || (ntwkOff.getGuestType() == GuestType.Isolated && !_networkModel.areServicesSupportedByNetworkOffering(ntwkOff.getId(), Service.SourceNat))); if (cidr == null && ip6Cidr == null && cidrRequired) { - if (ntwkOff.getGuestType() == GuestType.Shared) { - throw new InvalidParameterValueException(String.format("Gateway/netmask are required when creating %s networks.", Network.GuestType.Shared)); - } else { - throw new InvalidParameterValueException("gateway/netmask are required when create network of" + " type " + GuestType.Isolated + " with service " + Service.SourceNat.getName() + " disabled"); - } + throw new InvalidParameterValueException("StartIp/endIp/gateway/netmask are required when create network of" + " type " + Network.GuestType.Shared + + " and network of type " + GuestType.Isolated + " with service " + Service.SourceNat.getName() + " disabled"); } checkL2OfferingServices(ntwkOff); @@ -2744,7 +2491,7 @@ public Network doInTransaction(final TransactionStatus status) { userNetwork.setGateway(gateway); } - if (StringUtils.isNoneBlank(ip6Gateway, ip6Cidr)) { + if (StringUtils.isNotBlank(ip6Gateway) && StringUtils.isNotBlank(ip6Cidr)) { userNetwork.setIp6Cidr(ip6Cidr); userNetwork.setIp6Gateway(ip6Gateway); } @@ -2753,29 +2500,6 @@ public Network doInTransaction(final TransactionStatus status) { userNetwork.setExternalId(externalId); } - if (StringUtils.isNotBlank(routerIp)) { - userNetwork.setRouterIp(routerIp); - } - - if (StringUtils.isNotBlank(routerIpv6)) { - userNetwork.setRouterIpv6(routerIpv6); - } - - if (!GuestType.L2.equals(userNetwork.getGuestType())) { - if (StringUtils.isNotBlank(ip4Dns1)) { - userNetwork.setDns1(ip4Dns1); - } - if (StringUtils.isNotBlank(ip4Dns2)) { - userNetwork.setDns2(ip4Dns2); - } - if (StringUtils.isNotBlank(ip6Dns1)) { - userNetwork.setIp6Dns1(ip6Dns1); - } - if (StringUtils.isNotBlank(ip6Dns2)) { - userNetwork.setIp6Dns2(ip6Dns2); - } - } - if (vlanIdFinal != null) { if (isolatedPvlan == null) { URI uri = null; @@ -2783,14 +2507,8 @@ public Network doInTransaction(final TransactionStatus status) { //Logical router's UUID provided as VLAN_ID userNetwork.setVlanIdAsUUID(vlanIdFinal); //Set transient field } else { - uri = encodeVlanIdIntoBroadcastUri(vlanIdFinal, pNtwk); + uri = BroadcastDomainType.fromString(vlanIdFinal); } - - if (_networksDao.listByPhysicalNetworkPvlan(physicalNetworkId, uri.toString()).size() > 0) { - throw new InvalidParameterValueException("Network with vlan " + vlanIdFinal + - " already exists or overlaps with other network pvlans in zone " + zoneId); - } - userNetwork.setBroadcastUri(uri); if (!vlanIdFinal.equalsIgnoreCase(Vlan.UNTAGGED)) { userNetwork.setBroadcastDomainType(BroadcastDomainType.Vlan); @@ -2801,7 +2519,7 @@ public Network doInTransaction(final TransactionStatus status) { if (vlanIdFinal.equalsIgnoreCase(Vlan.UNTAGGED)) { throw new InvalidParameterValueException("Cannot support pvlan with untagged primary vlan!"); } - URI uri = NetUtils.generateUriForPvlan(vlanIdFinal, isolatedPvlan, isolatedPvlanType.toString()); + URI uri = NetUtils.generateUriForPvlan(vlanIdFinal, isolatedPvlan); if (_networksDao.listByPhysicalNetworkPvlan(physicalNetworkId, uri.toString(), isolatedPvlanType).size() > 0) { throw new InvalidParameterValueException("Network with primary vlan " + vlanIdFinal + " and secondary vlan " + isolatedPvlan + " type " + isolatedPvlanType + @@ -2812,8 +2530,10 @@ public Network doInTransaction(final TransactionStatus status) { userNetwork.setPvlanType(isolatedPvlanType); } } + final List networks = setupNetwork(owner, ntwkOff, userNetwork, plan, name, displayText, true, domainId, aclType, subdomainAccessFinal, vpcId, isDisplayNetworkEnabled); + Network network = null; if (networks == null || networks.isEmpty()) { throw new CloudRuntimeException("Fail to create a network"); @@ -2845,53 +2565,19 @@ public Network doInTransaction(final TransactionStatus status) { return network; } - @Override - public boolean isSharedNetworkWithoutSpecifyVlan(NetworkOffering offering) { - if (offering == null || offering.getTrafficType() != TrafficType.Guest || offering.getGuestType() != GuestType.Shared) { - return false; - } - return !offering.isSpecifyVlan(); - } - - private boolean isPrivateGatewayWithoutSpecifyVlan(NetworkOffering ntwkOff) { - return ntwkOff.getId() == _networkOfferingDao.findByUniqueName(NetworkOffering.SystemPrivateGatewayNetworkOfferingWithoutVlan).getId(); - } - - /** - * Encodes VLAN/VXLAN ID into a Broadcast URI according to the isolation method from the Physical Network. - * - * @return Broadcast URI, e.g. 'vlan://vlan_ID' or 'vxlan://vlxan_ID' - */ - protected URI encodeVlanIdIntoBroadcastUri(String vlanId, PhysicalNetwork pNtwk) { - if (pNtwk == null) { - throw new InvalidParameterValueException(String.format("Failed to encode VLAN/VXLAN %s into a Broadcast URI. Physical Network cannot be null.", vlanId)); - } - - if (!pNtwk.getIsolationMethods().isEmpty() && StringUtils.isNotBlank(pNtwk.getIsolationMethods().get(0))) { - String isolationMethod = pNtwk.getIsolationMethods().get(0).toLowerCase(); - String vxlan = BroadcastDomainType.Vxlan.toString().toLowerCase(); - if (isolationMethod.equals(vxlan)) { - return BroadcastDomainType.encodeStringIntoBroadcastUri(vlanId, BroadcastDomainType.Vxlan); - } - } - return BroadcastDomainType.fromString(vlanId); - } - /** * Checks bypass VLAN id/range overlap check during network creation for guest networks - * * @param bypassVlanOverlapCheck bypass VLAN id/range overlap check - * @param ntwkOff network offering + * @param ntwkOff network offering */ private boolean hasGuestBypassVlanOverlapCheck(final boolean bypassVlanOverlapCheck, final NetworkOfferingVO ntwkOff, final boolean isPrivateNetwork) { - return bypassVlanOverlapCheck && (ntwkOff.getGuestType() != GuestType.Isolated || isPrivateNetwork); + return bypassVlanOverlapCheck && (ntwkOff.getGuestType() == GuestType.Shared || isPrivateNetwork); } /** * Checks for L2 network offering services. Only 2 cases allowed: * - No services * - User Data service only, provided by ConfigDrive - * * @param ntwkOff network offering */ protected void checkL2OfferingServices(NetworkOfferingVO ntwkOff) { @@ -3017,7 +2703,7 @@ public boolean shutdownNetworkElementsAndResources(final ReservationContext cont boolean cleanupResult = true; boolean cleanupNeeded = false; try { - for (final Provider provider : providersToShutdown) { + for (final Provider provider: providersToShutdown) { if (provider.cleanupNeededOnShutdown()) { cleanupNeeded = true; break; @@ -3062,34 +2748,6 @@ public boolean shutdownNetworkElementsAndResources(final ReservationContext cont return success; } - private void cleanupPersistentnNetworkResources(NetworkVO network) { - long networkOfferingId = network.getNetworkOfferingId(); - NetworkOfferingVO offering = _networkOfferingDao.findById(networkOfferingId); - if (offering != null) { - if (networkMeetsPersistenceCriteria(network, offering, true) && - _networksDao.getOtherPersistentNetworksCount(network.getId(), network.getBroadcastUri().toString(), offering.isPersistent()) == 0) { - List hosts = resourceManager.listAllUpAndEnabledHostsInOneZoneByType(Host.Type.Routing, network.getDataCenterId()); - for (HostVO host : hosts) { - try { - NicTO to = createNicTOFromNetworkAndOffering(network, offering, host); - CleanupPersistentNetworkResourceCommand cmd = new CleanupPersistentNetworkResourceCommand(to); - CleanupPersistentNetworkResourceAnswer answer = (CleanupPersistentNetworkResourceAnswer) _agentMgr.send(host.getId(), cmd); - if (answer == null) { - s_logger.warn("Unable to get an answer to the CleanupPersistentNetworkResourceCommand from agent:" + host.getId()); - continue; - } - - if (!answer.getResult()) { - s_logger.warn("Unable to setup agent " + host.getId() + " due to " + answer.getDetails()); - } - } catch (Exception e) { - s_logger.warn("Failed to cleanup network resources on host: " + host.getName()); - } - } - } - } - } - @Override @DB public boolean destroyNetwork(final long networkId, final ReservationContext context, final boolean forced) { @@ -3129,8 +2787,6 @@ public boolean destroyNetwork(final long networkId, final ReservationContext con } } - cleanupPersistentnNetworkResources(network); - // Shutdown network first shutdownNetwork(networkId, context, false); @@ -3189,14 +2845,11 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { throw new CloudRuntimeException("Failed to trash network."); } - if (!deleteVlansInNetwork(networkFinal, context.getCaller().getId(), callerAccount)) { + if (!deleteVlansInNetwork(networkFinal.getId(), context.getCaller().getId(), callerAccount)) { s_logger.warn("Failed to delete network " + networkFinal + "; was unable to cleanup corresponding ip ranges"); throw new CloudRuntimeException("Failed to delete network " + networkFinal + "; was unable to cleanup corresponding ip ranges"); } else { // commit transaction only when ips and vlans for the network are released successfully - - ipv6Service.releaseIpv6SubnetForNetwork(networkId); - ipv6Service.removePublicIpv6PlaceholderNics(networkFinal); try { stateTransitTo(networkFinal, Event.DestroyNetwork); } catch (final NoTransitionException e) { @@ -3212,9 +2865,6 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { if (networkAccount != null) { _networkAccountDao.remove(networkAccount.getId()); } - - networkDetailsDao.removeDetails(networkFinal.getId()); - networkPermissionDao.removeAllPermissions(networkFinal.getId()); } final NetworkOffering ntwkOff = _entityMgr.findById(NetworkOffering.class, networkFinal.getNetworkOfferingId()); @@ -3247,8 +2897,8 @@ public boolean resourceCountNeedsUpdate(final NetworkOffering ntwkOff, final ACL return updateResourceCount; } - protected boolean deleteVlansInNetwork(final NetworkVO network, final long userId, final Account callerAccount) { - final long networkId = network.getId(); + protected boolean deleteVlansInNetwork(final long networkId, final long userId, final Account callerAccount) { + //cleanup Public vlans final List publicVlans = _vlanDao.listVlansByNetworkId(networkId); boolean result = true; @@ -3268,13 +2918,6 @@ protected boolean deleteVlansInNetwork(final NetworkVO network, final long userI _privateIpDao.deleteByNetworkId(networkId); s_logger.debug("Deleted ip range for private network id=" + networkId); } - - // release vlans of user-shared networks without specifyvlan - if (isSharedNetworkWithoutSpecifyVlan(_networkOfferingDao.findById(network.getNetworkOfferingId()))) { - s_logger.debug("Releasing vnet for the network id=" + network.getId()); - _dcDao.releaseVnet(BroadcastDomainType.getValue(network.getBroadcastUri()), network.getDataCenterId(), - network.getPhysicalNetworkId(), network.getAccountId(), network.getReservationId()); - } return result; } @@ -3306,12 +2949,8 @@ public void reallyRun() { s_logger.info("NetworkGarbageCollector uses '" + netGcWait + "' seconds for GC interval."); for (final Long networkId : networkIds) { - if (!_networkModel.isNetworkReadyForGc(networkId)) { - continue; - } - if (!networkDetailsDao.findDetails(Network.AssociatedNetworkId, String.valueOf(networkId), null).isEmpty()) { - s_logger.debug(String.format("Network %s is associated to a shared network, skipping", networkId)); + if (!_networkModel.isNetworkReadyForGc(networkId)) { continue; } @@ -3376,7 +3015,7 @@ public boolean startNetwork(final long networkId, final DeployDestination dest, // implement the network s_logger.debug("Starting network " + network + "..."); final Pair implementedNetwork = implementNetwork(networkId, dest, context); - if (implementedNetwork == null || implementedNetwork.first() == null) { + if (implementedNetwork== null || implementedNetwork.first() == null) { s_logger.warn("Failed to start the network " + network); return false; } else { @@ -3385,7 +3024,7 @@ public boolean startNetwork(final long networkId, final DeployDestination dest, } @Override - public boolean restartNetwork(final Long networkId, final Account callerAccount, final User callerUser, final boolean cleanup, final boolean livePatch) throws ConcurrentOperationException, ResourceUnavailableException, + public boolean restartNetwork(final Long networkId, final Account callerAccount, final User callerUser, final boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { boolean status = true; boolean restartRequired = false; @@ -3404,24 +3043,6 @@ public boolean restartNetwork(final Long networkId, final Account callerAccount, } setRestartRequired(network, restartRequired); return status; - } else if (livePatch) { - List domainRouters = routerDao.listByNetworkAndRole(network.getId(), VirtualRouter.Role.VIRTUAL_ROUTER, VirtualRouter.Role.INTERNAL_LB_VM); - for (DomainRouterVO router: domainRouters) { - try { - VMInstanceVO instanceVO = _vmDao.findById(router.getId()); - if (instanceVO == null) { - s_logger.info("Did not find a virtual router instance for the network"); - continue; - } - Pair patched = mgr.updateSystemVM(instanceVO, true); - if (patched.first()) { - s_logger.info(String.format("Successfully patched router %s", router)); - } - } catch (CloudRuntimeException e) { - throw new CloudRuntimeException(String.format("Failed to live patch router: %s", router), e); - } - - } } s_logger.debug("Implementing the network " + network + " elements and resources as a part of network restart without cleanup"); @@ -3531,10 +3152,10 @@ private boolean rollingRestartRouters(final NetworkVO network, final NetworkOffe return false; } s_logger.debug("Performing rolling restart of routers of network " + network); - destroyExpendableRouters(routerDao.findByNetwork(network.getId()), context); + destroyExpendableRouters(_routerDao.findByNetwork(network.getId()), context); final List providersToImplement = getNetworkProviders(network.getId()); - final List oldRouters = routerDao.findByNetwork(network.getId()); + final List oldRouters = _routerDao.findByNetwork(network.getId()); // Deploy a new router if (oldRouters.size() > 0) { @@ -3549,8 +3170,7 @@ private boolean rollingRestartRouters(final NetworkVO network, final NetworkOffe if (network.isRedundant() || (oldRouters.size() == 1 && oldRouters.get(0).getIsRedundantRouter())) { try { Thread.sleep(NetworkOrchestrationService.RVRHandoverTime); - } catch (final InterruptedException ignored) { - } + } catch (final InterruptedException ignored) {} } // Destroy old routers @@ -3567,7 +3187,7 @@ private boolean rollingRestartRouters(final NetworkVO network, final NetworkOffe implementNetworkElementsAndResources(dest, context, network, offering); } - return areRoutersRunning(routerDao.findByNetwork(network.getId())); + return areRoutersRunning(_routerDao.findByNetwork(network.getId())); } private void setRestartRequired(final NetworkVO network, final boolean restartRequired) { @@ -3599,7 +3219,7 @@ public UserDataServiceProvider getPasswordResetProvider(final Network network) { return null; } - return (UserDataServiceProvider) _networkModel.getElementImplementingProvider(passwordProvider); + return (UserDataServiceProvider)_networkModel.getElementImplementingProvider(passwordProvider); } @Override @@ -3611,7 +3231,7 @@ public UserDataServiceProvider getSSHKeyResetProvider(final Network network) { return null; } - return (UserDataServiceProvider) _networkModel.getElementImplementingProvider(SSHKeyProvider); + return (UserDataServiceProvider)_networkModel.getElementImplementingProvider(SSHKeyProvider); } @Override @@ -3624,8 +3244,8 @@ public DhcpServiceProvider getDhcpServiceProvider(final Network network) { } final NetworkElement element = _networkModel.getElementImplementingProvider(DhcpProvider); - if (element instanceof DhcpServiceProvider) { - return (DhcpServiceProvider) element; + if ( element instanceof DhcpServiceProvider ) { + return (DhcpServiceProvider)element; } else { return null; } @@ -3640,7 +3260,7 @@ public DnsServiceProvider getDnsServiceProvider(final Network network) { return null; } - return (DnsServiceProvider) _networkModel.getElementImplementingProvider(dnsProvider); + return (DnsServiceProvider) _networkModel.getElementImplementingProvider(dnsProvider); } protected boolean isSharedNetworkWithServices(final Network network) { @@ -3689,7 +3309,7 @@ public List listVmNics(final long vmId, final Long nicId, final L final NetworkGuruAdditionalFunctions guruFunctions = (NetworkGuruAdditionalFunctions) guru; final Map nsxParams = guruFunctions.listAdditionalNicParams(nic.getUuid()); - if (nsxParams != null) { + if (nsxParams != null){ final String lswitchUuuid = nsxParams.containsKey(NetworkGuruAdditionalFunctions.NSX_LSWITCH_UUID) ? (String) nsxParams.get(NetworkGuruAdditionalFunctions.NSX_LSWITCH_UUID) : null; final String lswitchPortUuuid = nsxParams.containsKey(NetworkGuruAdditionalFunctions.NSX_LSWITCHPORT_UUID) @@ -3807,8 +3427,6 @@ private boolean cleanupNetworkResources(final long networkId, final Account call throw new CloudRuntimeException("We should never get to here because we used true when applyIpAssociations", e); } - annotationDao.removeByEntityType(AnnotationService.EntityType.NETWORK.name(), network.getUuid()); - return success; } @@ -4015,7 +3633,7 @@ public void processConnect(final Host host, final StartupCommand cmd, final bool return; } final long hostId = host.getId(); - final StartupRoutingCommand startup = (StartupRoutingCommand) cmd; + final StartupRoutingCommand startup = (StartupRoutingCommand)cmd; final String dataCenter = startup.getDataCenter(); @@ -4068,7 +3686,7 @@ public void processConnect(final Host host, final StartupCommand cmd, final bool } final CheckNetworkCommand nwCmd = new CheckNetworkCommand(networkInfoList); - final CheckNetworkAnswer answer = (CheckNetworkAnswer) _agentMgr.easySend(hostId, nwCmd); + final CheckNetworkAnswer answer = (CheckNetworkAnswer)_agentMgr.easySend(hostId, nwCmd); if (answer == null) { s_logger.warn("Unable to get an answer to the CheckNetworkCommand from agent:" + host.getId()); @@ -4076,7 +3694,7 @@ public void processConnect(final Host host, final StartupCommand cmd, final bool } if (!answer.getResult()) { - s_logger.warn("Unable to setup agent " + hostId + " due to " + answer.getDetails()); + s_logger.warn("Unable to setup agent " + hostId + " due to " + answer.getDetails() ); final String msg = "Incorrect Network setup on agent, Reinitialize agent after network names are setup, details : " + answer.getDetails(); _alertMgr.sendAlert(AlertManager.AlertType.ALERT_TYPE_HOST, dcId, host.getPodId(), msg, msg); throw new ConnectionException(true, msg); @@ -4203,6 +3821,7 @@ protected NicProfile getNicProfileForVm(final Network network, final NicProfile public NicProfile createNicForVm(final Network network, final NicProfile requested, final ReservationContext context, final VirtualMachineProfile vmProfile, final boolean prepare) throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException, ConcurrentOperationException, InsufficientCapacityException, ResourceUnavailableException { + final VirtualMachine vm = vmProfile.getVirtualMachine(); final DataCenter dc = _entityMgr.findById(DataCenter.class, network.getDataCenterId()); final Host host = _hostDao.findById(vm.getHostId()); @@ -4221,7 +3840,7 @@ public NicProfile createNicForVm(final Network network, final NicProfile request } //Update vm_network_map table - if (vmProfile.getType() == VirtualMachine.Type.User) { + if(vmProfile.getType() == VirtualMachine.Type.User) { final VMNetworkMapVO vno = new VMNetworkMapVO(vm.getId(), network.getId()); _vmNetworkMapDao.persist(vno); } @@ -4285,12 +3904,11 @@ public Map getSystemVMAccessDetails(final VirtualMachine vm) { if (network.getTrafficType() == Networks.TrafficType.Management) { privateIpAddress = address; } - if (network.getTrafficType() != null && StringUtils.isNotEmpty(address)) { + if (network.getTrafficType() != null && !Strings.isNullOrEmpty(address)) { accessDetails.put(network.getTrafficType().name(), address); } } - - if (privateIpAddress != null && StringUtils.isEmpty(accessDetails.get(NetworkElementCommand.ROUTER_IP))) { + if (privateIpAddress != null && Strings.isNullOrEmpty(accessDetails.get(NetworkElementCommand.ROUTER_IP))) { accessDetails.put(NetworkElementCommand.ROUTER_IP, privateIpAddress); } return accessDetails; @@ -4355,7 +3973,7 @@ public StaticNatServiceProvider getStaticNatProviderForNetwork(final Network net //only one provider per Static nat service is supoprted final NetworkElement element = getElementForServiceInNetwork(network, Service.StaticNat).get(0); assert element instanceof StaticNatServiceProvider; - return (StaticNatServiceProvider) element; + return (StaticNatServiceProvider)element; } @Override @@ -4381,7 +3999,7 @@ public LoadBalancingServiceProvider getLoadBalancingProviderForNetwork(final Net assert lbElement != null; assert lbElement instanceof LoadBalancingServiceProvider; - return (LoadBalancingServiceProvider) lbElement; + return (LoadBalancingServiceProvider)lbElement; } @Override @@ -4415,20 +4033,10 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { @Override public NicVO savePlaceholderNic(final Network network, final String ip4Address, final String ip6Address, final Type vmType) { - return savePlaceholderNic(network, ip4Address, ip6Address, null, null, null, vmType); - } - - @Override - public NicVO savePlaceholderNic(final Network network, final String ip4Address, final String ip6Address, final String ip6Cidr, final String ip6Gateway, final String reserver, final Type vmType) { final NicVO nic = new NicVO(null, null, network.getId(), null); nic.setIPv4Address(ip4Address); nic.setIPv6Address(ip6Address); - nic.setIPv6Cidr(ip6Cidr); - nic.setIPv6Gateway(ip6Gateway); nic.setReservationStrategy(ReservationStrategy.PlaceHolder); - if (reserver != null) { - nic.setReserver(reserver); - } nic.setState(Nic.State.Reserved); nic.setVmType(vmType); return _nicDao.persist(nic); @@ -4440,7 +4048,7 @@ public Pair importNic(final String macAddress, int deviceId throws ConcurrentOperationException, InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { s_logger.debug("Allocating nic for vm " + vm.getUuid() + " in network " + network + " during import"); String guestIp = null; - if (ipAddresses != null && StringUtils.isNotEmpty(ipAddresses.getIp4Address())) { + if (ipAddresses != null && !Strings.isNullOrEmpty(ipAddresses.getIp4Address())) { if (ipAddresses.getIp4Address().equals("auto")) { ipAddresses.setIp4Address(null); } @@ -4472,10 +4080,10 @@ public NicVO doInTransaction(TransactionStatus status) { NicVO vo = new NicVO(network.getGuruName(), vm.getId(), network.getId(), vm.getType()); vo.setMacAddress(macAddress); vo.setAddressFormat(Networks.AddressFormat.Ip4); - if (NetUtils.isValidIp4(finalGuestIp) && StringUtils.isNotEmpty(network.getGateway())) { + if (NetUtils.isValidIp4(finalGuestIp) && !Strings.isNullOrEmpty(network.getGateway())) { vo.setIPv4Address(finalGuestIp); vo.setIPv4Gateway(network.getGateway()); - if (StringUtils.isNotEmpty(network.getCidr())) { + if (!Strings.isNullOrEmpty(network.getCidr())) { vo.setIPv4Netmask(NetUtils.cidr2Netmask(network.getCidr())); } } @@ -4540,8 +4148,8 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[]{NetworkGcWait, NetworkGcInterval, NetworkLockTimeout, + return new ConfigKey[] {NetworkGcWait, NetworkGcInterval, NetworkLockTimeout, GuestDomainSuffix, NetworkThrottlingRate, MinVRVersion, - PromiscuousMode, MacAddressChanges, ForgedTransmits, MacLearning, RollingRestartEnabled}; + PromiscuousMode, MacAddressChanges, ForgedTransmits, RollingRestartEnabled}; } } diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java b/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java index e6869b4b264b..e25c83293bdb 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java @@ -16,9 +16,14 @@ // under the License. package com.cloud.network.dao; -import java.net.URI; -import java.util.Date; -import java.util.UUID; +import com.cloud.network.Network; +import com.cloud.network.Networks.BroadcastDomainType; +import com.cloud.network.Networks.Mode; +import com.cloud.network.Networks.TrafficType; +import com.cloud.utils.NumbersUtil; +import com.cloud.utils.db.GenericDao; +import com.cloud.utils.net.NetUtils; +import org.apache.cloudstack.acl.ControlledEntity; import javax.persistence.Column; import javax.persistence.Entity; @@ -28,17 +33,9 @@ import javax.persistence.Table; import javax.persistence.TableGenerator; import javax.persistence.Transient; - -import org.apache.cloudstack.acl.ControlledEntity; -import org.apache.commons.lang3.StringUtils; - -import com.cloud.network.Network; -import com.cloud.network.Networks.BroadcastDomainType; -import com.cloud.network.Networks.Mode; -import com.cloud.network.Networks.TrafficType; -import com.cloud.utils.NumbersUtil; -import com.cloud.utils.db.GenericDao; -import com.cloud.utils.net.NetUtils; +import java.net.URI; +import java.util.Date; +import java.util.UUID; /** * NetworkConfigurationVO contains information about a specific network. @@ -88,6 +85,9 @@ public class NetworkVO implements Network { @Column(name = "vpc_id") Long vpcId; + @Column(name = "tungsten_network_uuid") + String tungstenNetworkUuid; + @Column(name = "physical_network_id") Long physicalNetworkId; @@ -107,6 +107,9 @@ public class NetworkVO implements Network { @Column(name = "redundant") boolean redundant; + @Column(name = "dns1") + String dns1; + @Column(name = "domain_id") long domainId; @@ -123,18 +126,9 @@ public class NetworkVO implements Network { @Column(name = "guru_data", length = 1024) String guruData; - @Column(name = "dns1") - String dns1; - @Column(name = "dns2") String dns2; - @Column(name = "ip6Dns1") - String ip6Dns1; - - @Column(name = "ip6Dns2") - String ip6Dns2; - @Column(name = "network_domain") String networkDomain; @@ -182,12 +176,6 @@ public class NetworkVO implements Network { @Column(name = "external_id") String externalId; - @Transient - String routerIp; - - @Transient - String routerIpv6; - @Transient transient String vlanIdAsUUID; @@ -212,7 +200,7 @@ public NetworkVO() { * @param physicalNetworkId TODO */ public NetworkVO(TrafficType trafficType, Mode mode, BroadcastDomainType broadcastDomainType, long networkOfferingId, State state, long dataCenterId, - Long physicalNetworkId, final boolean isRedundant) { + Long physicalNetworkId, final boolean isRedundant) { this.trafficType = trafficType; this.mode = mode; this.broadcastDomainType = broadcastDomainType; @@ -230,25 +218,25 @@ public NetworkVO(TrafficType trafficType, Mode mode, BroadcastDomainType broadca } public NetworkVO(long id, Network that, long offeringId, String guruName, long domainId, long accountId, long related, String name, String displayText, - String networkDomain, GuestType guestType, long dcId, Long physicalNetworkId, ACLType aclType, boolean specifyIpRanges, Long vpcId, final boolean isRedundant, String externalId) { + String networkDomain, GuestType guestType, long dcId, Long physicalNetworkId, ACLType aclType, boolean specifyIpRanges, Long vpcId, final boolean isRedundant, String externalId) { this(id, - that.getTrafficType(), - that.getMode(), - that.getBroadcastDomainType(), - offeringId, - domainId, - accountId, - related, - name, - displayText, - networkDomain, - guestType, - dcId, - physicalNetworkId, - aclType, - specifyIpRanges, - vpcId, - isRedundant); + that.getTrafficType(), + that.getMode(), + that.getBroadcastDomainType(), + offeringId, + domainId, + accountId, + related, + name, + displayText, + networkDomain, + guestType, + dcId, + physicalNetworkId, + aclType, + specifyIpRanges, + vpcId, + isRedundant); gateway = that.getGateway(); cidr = that.getCidr(); networkCidr = that.getNetworkCidr(); @@ -262,18 +250,6 @@ public NetworkVO(long id, Network that, long offeringId, String guruName, long d uuid = UUID.randomUUID().toString(); ip6Gateway = that.getIp6Gateway(); ip6Cidr = that.getIp6Cidr(); - if (StringUtils.isNotBlank(that.getDns1())) { - this.dns1 = that.getDns1(); - } - if (StringUtils.isNotBlank(that.getDns2())) { - this.dns2 = that.getDns2(); - } - if (StringUtils.isNotBlank(that.getIp6Dns1())) { - this.ip6Dns1 = that.getIp6Dns1(); - } - if (StringUtils.isNotBlank(that.getIp6Dns2())) { - this.ip6Dns2 = that.getIp6Dns2(); - } this.externalId = externalId; } @@ -295,8 +271,8 @@ public NetworkVO(long id, Network that, long offeringId, String guruName, long d * @param dataCenterId */ public NetworkVO(long id, TrafficType trafficType, Mode mode, BroadcastDomainType broadcastDomainType, long networkOfferingId, long domainId, long accountId, - long related, String name, String displayText, String networkDomain, GuestType guestType, long dcId, Long physicalNetworkId, ACLType aclType, - boolean specifyIpRanges, Long vpcId, final boolean isRedundant) { + long related, String name, String displayText, String networkDomain, GuestType guestType, long dcId, Long physicalNetworkId, ACLType aclType, + boolean specifyIpRanges, Long vpcId, final boolean isRedundant) { this(trafficType, mode, broadcastDomainType, networkOfferingId, State.Allocated, dcId, physicalNetworkId, isRedundant); this.domainId = domainId; this.accountId = accountId; @@ -312,6 +288,26 @@ public NetworkVO(long id, TrafficType trafficType, Mode mode, BroadcastDomainTyp this.vpcId = vpcId; } + public NetworkVO(long id, TrafficType trafficType, Mode mode, BroadcastDomainType broadcastDomainType, long networkOfferingId, long domainId, long accountId, + long related, String name, String displayText, String networkDomain, GuestType guestType, long dcId, Long physicalNetworkId, ACLType aclType, + boolean specifyIpRanges, Long vpcId, final boolean isRedundant, String tungstenNetworkUuid) { + this(trafficType, mode, broadcastDomainType, networkOfferingId, State.Allocated, dcId, physicalNetworkId, isRedundant); + this.domainId = domainId; + this.accountId = accountId; + this.related = related; + this.id = id; + this.name = name; + this.displayText = displayText; + this.aclType = aclType; + this.networkDomain = networkDomain; + uuid = UUID.randomUUID().toString(); + this.guestType = guestType; + this.specifyIpRanges = specifyIpRanges; + this.vpcId = vpcId; + this.tungstenNetworkUuid = tungstenNetworkUuid; + + } + @Override public String getReservationId() { return reservationId; @@ -422,6 +418,15 @@ public TrafficType getTrafficType() { return trafficType; } + @Override + public String getTungstenNetworkUuid() { + return tungstenNetworkUuid; + } + + public void setTungstenNetworkUuid(String tungstenNetworkUuid) { + this.tungstenNetworkUuid = tungstenNetworkUuid; + } + @Override public void setTrafficType(TrafficType trafficType) { this.trafficType = trafficType; @@ -490,7 +495,6 @@ public long getDataCenterId() { return dataCenterId; } - @Override public String getDns1() { return dns1; } @@ -499,7 +503,6 @@ public void setDns1(String dns) { dns1 = dns; } - @Override public String getDns2() { return dns2; } @@ -508,24 +511,6 @@ public void setDns2(String dns) { dns2 = dns; } - @Override - public String getIp6Dns1() { - return ip6Dns1; - } - - public void setIp6Dns1(String ip6Dns1) { - this.ip6Dns1 = ip6Dns1; - } - - @Override - public String getIp6Dns2() { - return ip6Dns2; - } - - public void setIp6Dns2(String ip6Dns2) { - this.ip6Dns2 = ip6Dns2; - } - @Override public String getName() { return name; @@ -588,7 +573,9 @@ public boolean equals(Object obj) { @Override public String toString() { - return String.format("Network {\"id\": %s, \"name\": \"%s\", \"uuid\": \"%s\", \"networkofferingid\": %d}", id, name, uuid, networkOfferingId); + StringBuilder buf = new StringBuilder("Ntwk["); + buf.append(id).append("|").append(trafficType).append("|").append(networkOfferingId).append("]"); + return buf.toString(); } @Override @@ -715,20 +702,4 @@ public PVlanType getPvlanType() { public void setPvlanType(PVlanType pvlanType) { this.pVlanType = pvlanType; } - - public String getRouterIp() { - return routerIp; - } - - public void setRouterIp(String routerIp) { - this.routerIp = routerIp; - } - - public String getRouterIpv6() { - return routerIpv6; - } - - public void setRouterIpv6(String routerIpv6) { - this.routerIpv6 = routerIpv6; - } } diff --git a/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java b/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java index ff187687fdf4..aaa2bf485b26 100644 --- a/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java +++ b/engine/schema/src/main/java/com/cloud/offerings/NetworkOfferingVO.java @@ -133,6 +133,9 @@ public class NetworkOfferingVO implements NetworkOffering { @Column(name = "for_vpc") boolean forVpc; + @Column(name = "for_tungsten") + boolean forTungsten; + @Column(name = "egress_default_policy") boolean egressdefaultpolicy; @@ -180,6 +183,15 @@ public void setForVpc(boolean isForVpc) { this.forVpc = isForVpc; } + @Override + public boolean isForTungsten() { + return forTungsten; + } + + public void setForTungsten(boolean forTungsten) { + this.forTungsten = forTungsten; + } + @Override public long getId() { return id; @@ -324,8 +336,8 @@ public boolean isEgressDefaultPolicy() { } public NetworkOfferingVO(String name, String displayText, TrafficType trafficType, boolean systemOnly, boolean specifyVlan, Integer rateMbps, - Integer multicastRateMbps, boolean isDefault, Availability availability, String tags, Network.GuestType guestType, boolean conserveMode, - boolean specifyIpRanges, boolean isPersistent, boolean internalLb, boolean publicLb, boolean isForVpc) { + Integer multicastRateMbps, boolean isDefault, Availability availability, String tags, Network.GuestType guestType, boolean conserveMode, + boolean specifyIpRanges, boolean isPersistent, boolean internalLb, boolean publicLb, boolean isForVpc) { this.name = name; this.displayText = displayText; this.rateMbps = rateMbps; @@ -355,25 +367,25 @@ public NetworkOfferingVO(String name, String displayText, TrafficType trafficTyp } public NetworkOfferingVO(String name, String displayText, TrafficType trafficType, boolean systemOnly, boolean specifyVlan, Integer rateMbps, - Integer multicastRateMbps, boolean isDefault, Availability availability, String tags, Network.GuestType guestType, boolean conserveMode, boolean dedicatedLb, - boolean sharedSourceNat, boolean redundantRouter, boolean elasticIp, boolean elasticLb, boolean specifyIpRanges, boolean inline, boolean isPersistent, - boolean associatePublicIP, boolean publicLb, boolean internalLb, boolean isForVpc, boolean egressdefaultpolicy, boolean supportsStrechedL2, boolean supportsPublicAccess) { + Integer multicastRateMbps, boolean isDefault, Availability availability, String tags, Network.GuestType guestType, boolean conserveMode, boolean dedicatedLb, + boolean sharedSourceNat, boolean redundantRouter, boolean elasticIp, boolean elasticLb, boolean specifyIpRanges, boolean inline, boolean isPersistent, + boolean associatePublicIP, boolean publicLb, boolean internalLb, boolean isForVpc, boolean egressdefaultpolicy, boolean supportsStrechedL2, boolean supportsPublicAccess) { this(name, - displayText, - trafficType, - systemOnly, - specifyVlan, - rateMbps, - multicastRateMbps, - isDefault, - availability, - tags, - guestType, - conserveMode, - specifyIpRanges, - isPersistent, - internalLb, - publicLb, isForVpc); + displayText, + trafficType, + systemOnly, + specifyVlan, + rateMbps, + multicastRateMbps, + isDefault, + availability, + tags, + guestType, + conserveMode, + specifyIpRanges, + isPersistent, + internalLb, + publicLb, isForVpc); this.dedicatedLB = dedicatedLb; this.sharedSourceNat = sharedSourceNat; this.redundantRouter = redundantRouter; @@ -402,24 +414,24 @@ public NetworkOfferingVO(String name, TrafficType trafficType, boolean specifyIp this.state = State.Enabled; } - public NetworkOfferingVO(String name, Network.GuestType guestType, boolean specifyVlan) { + public NetworkOfferingVO(String name, Network.GuestType guestType) { this(name, - "System Offering for " + name, - TrafficType.Guest, - true, - specifyVlan, - 0, - 0, - true, - Availability.Optional, - null, - Network.GuestType.Isolated, - true, - false, - false, - false, - false, - false); + "System Offering for " + name, + TrafficType.Guest, + true, + true, + 0, + 0, + true, + Availability.Optional, + null, + Network.GuestType.Isolated, + true, + false, + false, + false, + false, + false); this.state = State.Enabled; } diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql b/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql index a2db61b3f2dd..ca0226724df6 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql @@ -18,489 +18,52 @@ --; -- Schema upgrade from 4.14.0.0 to 4.15.0.0 --; +ALTER TABLE `cloud`.`network_offerings` ADD COLUMN `for_tungsten` int(1) unsigned DEFAULT '0' COMMENT 'is tungsten enabled for the resource'; +ALTER TABLE `cloud`.`networks` ADD COLUMN `tungsten_network_uuid` varchar(255) COMMENT 'tungsten id'; --- Project roles -CREATE TABLE IF NOT EXISTS `cloud`.`project_role` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `uuid` varchar(255) UNIQUE, - `name` varchar(255) COMMENT 'unique name of the dynamic project role', - `removed` datetime COMMENT 'date removed', - `description` text COMMENT 'description of the project role', - `project_id` bigint(20) unsigned COMMENT 'Id of the project to which the role belongs', - PRIMARY KEY (`id`), - KEY `i_project_role__name` (`name`), - UNIQUE KEY (`name`, `project_id`), - CONSTRAINT `fk_project_role__project_id` FOREIGN KEY(`project_id`) REFERENCES `projects`(`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- Project role permissions table -CREATE TABLE IF NOT EXISTS `cloud`.`project_role_permissions` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `uuid` varchar(255) UNIQUE, - `project_id` bigint(20) unsigned NOT NULL COMMENT 'id of the role', - `project_role_id` bigint(20) unsigned NOT NULL COMMENT 'id of the role', - `rule` varchar(255) NOT NULL COMMENT 'rule for the role, api name or wildcard', - `permission` varchar(255) NOT NULL COMMENT 'access authority, allow or deny', - `description` text COMMENT 'description of the rule', - `sort_order` bigint(20) unsigned NOT NULL DEFAULT 0 COMMENT 'permission sort order', - PRIMARY KEY (`id`), - KEY `fk_project_role_permissions__project_role_id` (`project_role_id`), - KEY `i_project_role_permissions__sort_order` (`sort_order`), - UNIQUE KEY (`project_role_id`, `rule`), - CONSTRAINT `fk_project_role_permissions__project_id` FOREIGN KEY(`project_id`) REFERENCES `projects`(`id`) ON DELETE CASCADE, - CONSTRAINT `fk_project_role_permissions__project_role_id` FOREIGN KEY (`project_role_id`) REFERENCES `project_role` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - --- Alter project accounts table to include user_id and project_role_id for role based users in projects -ALTER TABLE `cloud`.`project_account` - ADD COLUMN `user_id` bigint unsigned COMMENT 'ID of user to be added to the project' AFTER `account_id`, - ADD CONSTRAINT `fk_project_account__user_id` FOREIGN KEY `fk_project_account__user_id`(`user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE, - ADD COLUMN `project_role_id` bigint unsigned COMMENT 'Project role id' AFTER `project_account_id`, - ADD CONSTRAINT `fk_project_account__project_role_id` FOREIGN KEY (`project_role_id`) REFERENCES `project_role` (`id`) ON DELETE SET NULL, - DROP FOREIGN KEY `fk_project_account__account_id`, - DROP INDEX `account_id`; - -ALTER TABLE `cloud`.`project_account` - ADD CONSTRAINT `fk_project_account__account_id` FOREIGN KEY(`account_id`) REFERENCES `account`(`id`) ON DELETE CASCADE , - ADD CONSTRAINT `uc_project_account__project_id_account_id_user_id` UNIQUE (`project_id`, `account_id`, `user_id`) ; - --- Alter project invitations table to include user_id for invites sent to specific users of an account -ALTER TABLE `cloud`.`project_invitations` - ADD COLUMN `user_id` bigint unsigned COMMENT 'ID of user to be added to the project' AFTER `account_id`, - ADD COLUMN `account_role` varchar(255) NOT NULL DEFAULT 'Regular' COMMENT 'Account role in the project (Owner or Regular)' AFTER `domain_id`, - ADD COLUMN `project_role_id` bigint unsigned COMMENT 'Project role id' AFTER `account_role`, - ADD CONSTRAINT `fk_project_invitations__user_id` FOREIGN KEY (`user_id`) REFERENCES `user`(`id`) ON DELETE CASCADE, - ADD CONSTRAINT `fk_project_invitations__project_role_id` FOREIGN KEY (`project_role_id`) REFERENCES `project_role` (`id`) ON DELETE SET NULL, - DROP INDEX `project_id`, - ADD CONSTRAINT `uc_project_invitations__project_id_account_id_user_id` UNIQUE (`project_id`, `account_id`,`user_id`); - --- Alter project_invitation_view to incorporate user_id as a field -DROP VIEW IF EXISTS `cloud`.`project_invitation_view`; -CREATE VIEW `cloud`.`project_invitation_view` AS - select - project_invitations.id, - project_invitations.uuid, - project_invitations.email, - project_invitations.created, - project_invitations.state, - project_invitations.project_role_id, - projects.id project_id, - projects.uuid project_uuid, - projects.name project_name, - account.id account_id, - account.uuid account_uuid, - account.account_name, - account.type account_type, - user.id user_id, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path - from - `cloud`.`project_invitations` - left join - `cloud`.`account` ON project_invitations.account_id = account.id - left join - `cloud`.`domain` ON project_invitations.domain_id = domain.id - left join - `cloud`.`projects` ON projects.id = project_invitations.project_id - left join - `cloud`.`user` ON project_invitations.user_id = user.id; - --- Alter project_account_view to incorporate user id -DROP VIEW IF EXISTS `cloud`.`project_account_view`; -CREATE VIEW `cloud`.`project_account_view` AS - select - project_account.id, - account.id account_id, - account.uuid account_uuid, - account.account_name, - account.type account_type, - user.id user_id, - user.uuid user_uuid, - user.username user_name, - project_account.account_role, - project_role.id project_role_id, - project_role.uuid project_role_uuid, - projects.id project_id, - projects.uuid project_uuid, - projects.name project_name, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path - from - `cloud`.`project_account` - inner join - `cloud`.`account` ON project_account.account_id = account.id - inner join - `cloud`.`domain` ON account.domain_id = domain.id - inner join - `cloud`.`projects` ON projects.id = project_account.project_id - left join - `cloud`.`project_role` ON project_account.project_role_id = project_role.id - left join - `cloud`.`user` ON (project_account.user_id = user.id); - --- Alter project_view to incorporate user id -DROP VIEW IF EXISTS `cloud`.`project_view`; -CREATE VIEW `cloud`.`project_view` AS - select - projects.id, - projects.uuid, - projects.name, - projects.display_text, - projects.state, - projects.removed, - projects.created, - projects.project_account_id, - account.account_name owner, - pacct.account_id, - pacct.user_id, - domain.id domain_id, - domain.uuid domain_uuid, - domain.name domain_name, - domain.path domain_path - from - `cloud`.`projects` - inner join - `cloud`.`domain` ON projects.domain_id = domain.id - inner join - `cloud`.`project_account` ON projects.id = project_account.project_id - and project_account.account_role = 'Admin' - inner join - `cloud`.`account` ON account.id = project_account.account_id - left join - `cloud`.`project_account` pacct ON projects.id = pacct.project_id; - --- Fix Debian 10 32-bit hypervisor mappings on VMware, debian10-32bit OS ID in guest_os table is 292, not 282 -UPDATE `cloud`.`guest_os_hypervisor` SET guest_os_id=292 WHERE guest_os_id=282 AND hypervisor_type="VMware" AND guest_os_name="debian10Guest"; --- Fix CentOS 32-bit mapping for VMware 5.5 which does not have a centos6Guest but only centosGuest and centos64Guest -UPDATE `cloud`.`guest_os_hypervisor` SET guest_os_name='centosGuest' where hypervisor_type="VMware" and hypervisor_version="5.5" and guest_os_name="centos6Guest"; - -ALTER TABLE `cloud`.`roles` ADD COLUMN `is_default` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'is this a default role'; -UPDATE `cloud`.`roles` SET `is_default` = 1 WHERE id IN (1, 2, 3, 4); - --- Updated Default CloudStack roles with read-only and support admin and user roles -INSERT INTO `cloud`.`roles` (`uuid`, `name`, `role_type`, `description`, `is_default`) VALUES (UUID(), 'Read-Only Admin - Default', 'Admin', 'Default read-only admin role', 1); -INSERT INTO `cloud`.`roles` (`uuid`, `name`, `role_type`, `description`, `is_default`) VALUES (UUID(), 'Read-Only User - Default', 'User', 'Default read-only user role', 1); -INSERT INTO `cloud`.`roles` (`uuid`, `name`, `role_type`, `description`, `is_default`) VALUES (UUID(), 'Support Admin - Default', 'Admin', 'Default support admin role', 1); -INSERT INTO `cloud`.`roles` (`uuid`, `name`, `role_type`, `description`, `is_default`) VALUES (UUID(), 'Support User - Default', 'User', 'Default support user role', 1); - --- mysql8 nics table fix for newer distributions -ALTER TABLE `cloud`.`nics` MODIFY COLUMN update_time timestamp DEFAULT CURRENT_TIMESTAMP; - --- Change guest OS name to support default CentOS 5 template in XenServer8.0 -UPDATE `cloud`.`guest_os_hypervisor` SET guest_os_name='CentOS 7' where guest_os_id=(SELECT guest_os_id from `cloud`.`vm_template` WHERE unique_name='centos56-x86_64-xen') AND hypervisor_type='Xenserver' AND hypervisor_version='8.0.0'; - --- Add XenServer 8.1 hypervisor capabilities -INSERT INTO `cloud`.`hypervisor_capabilities`(uuid, hypervisor_type, hypervisor_version, max_guests_limit, max_data_volumes_limit, max_hosts_per_cluster, storage_motion_supported) values (UUID(), 'XenServer', '8.1.0', 1000, 253, 64, 1); - --- Copy XenServer 8.0 hypervisor guest OS mappings to XenServer8.1 -INSERT INTO `cloud`.`guest_os_hypervisor` (uuid,hypervisor_type, hypervisor_version, guest_os_name, guest_os_id, created, is_user_defined) SELECT UUID(),'Xenserver', '8.1.0', guest_os_name, guest_os_id, now(), 0 FROM `cloud`.`guest_os_hypervisor` WHERE hypervisor_type='Xenserver' AND hypervisor_version='8.0.0'; - -CREATE TABLE IF NOT EXISTS `cloud`.`vsphere_storage_policy` ( - `id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, - `uuid` varchar(255) UNIQUE, - `zone_id` bigint(20) unsigned NOT NULL COMMENT 'id of the zone', - `policy_id` varchar(255) NOT NULL COMMENT 'the identifier of the Storage Policy in vSphere DataCenter', - `name` varchar(255) NOT NULL COMMENT 'name of the storage policy', - `description` text COMMENT 'description of the storage policy', - `update_time` datetime COMMENT 'last updated when policy imported', - `removed` datetime COMMENT 'date removed', - PRIMARY KEY (`id`), - KEY `fk_vsphere_storage_policy__zone_id` (`zone_id`), - UNIQUE KEY (`zone_id`, `policy_id`), - CONSTRAINT `fk_vsphere_storage_policy__zone_id` FOREIGN KEY (`zone_id`) REFERENCES `data_center` (`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -ALTER TABLE `cloud`.`storage_pool` ADD COLUMN `parent` BIGINT(20) UNSIGNED NOT NULL DEFAULT 0 COMMENT 'ID of the Datastore cluster (storage pool) if this is a child in that Datastore cluster'; - --- Added parent column to support datastore clusters in vmware vsphere -DROP VIEW IF EXISTS `cloud`.`storage_pool_view`; -CREATE VIEW `cloud`.`storage_pool_view` AS - SELECT - `storage_pool`.`id` AS `id`, - `storage_pool`.`uuid` AS `uuid`, - `storage_pool`.`name` AS `name`, - `storage_pool`.`status` AS `status`, - `storage_pool`.`path` AS `path`, - `storage_pool`.`pool_type` AS `pool_type`, - `storage_pool`.`host_address` AS `host_address`, - `storage_pool`.`created` AS `created`, - `storage_pool`.`removed` AS `removed`, - `storage_pool`.`capacity_bytes` AS `capacity_bytes`, - `storage_pool`.`capacity_iops` AS `capacity_iops`, - `storage_pool`.`scope` AS `scope`, - `storage_pool`.`hypervisor` AS `hypervisor`, - `storage_pool`.`storage_provider_name` AS `storage_provider_name`, - `storage_pool`.`parent` AS `parent`, - `cluster`.`id` AS `cluster_id`, - `cluster`.`uuid` AS `cluster_uuid`, - `cluster`.`name` AS `cluster_name`, - `cluster`.`cluster_type` AS `cluster_type`, - `data_center`.`id` AS `data_center_id`, - `data_center`.`uuid` AS `data_center_uuid`, - `data_center`.`name` AS `data_center_name`, - `data_center`.`networktype` AS `data_center_type`, - `host_pod_ref`.`id` AS `pod_id`, - `host_pod_ref`.`uuid` AS `pod_uuid`, - `host_pod_ref`.`name` AS `pod_name`, - `storage_pool_tags`.`tag` AS `tag`, - `op_host_capacity`.`used_capacity` AS `disk_used_capacity`, - `op_host_capacity`.`reserved_capacity` AS `disk_reserved_capacity`, - `async_job`.`id` AS `job_id`, - `async_job`.`uuid` AS `job_uuid`, - `async_job`.`job_status` AS `job_status`, - `async_job`.`account_id` AS `job_account_id` - FROM - ((((((`storage_pool` - LEFT JOIN `cluster` ON ((`storage_pool`.`cluster_id` = `cluster`.`id`))) - LEFT JOIN `data_center` ON ((`storage_pool`.`data_center_id` = `data_center`.`id`))) - LEFT JOIN `host_pod_ref` ON ((`storage_pool`.`pod_id` = `host_pod_ref`.`id`))) - LEFT JOIN `storage_pool_tags` ON (((`storage_pool_tags`.`pool_id` = `storage_pool`.`id`)))) - LEFT JOIN `op_host_capacity` ON (((`storage_pool`.`id` = `op_host_capacity`.`host_id`) - AND (`op_host_capacity`.`capacity_type` IN (3 , 9))))) - LEFT JOIN `async_job` ON (((`async_job`.`instance_id` = `storage_pool`.`id`) - AND (`async_job`.`instance_type` = 'StoragePool') - AND (`async_job`.`job_status` = 0)))); - --- Add passthrough instruction for appliance deployments -ALTER TABLE `cloud`.`vm_template` ADD COLUMN `deploy_as_is` tinyint(1) NOT NULL DEFAULT '0' COMMENT 'True if the template should be deployed with disks and networks as defined by OVF'; - --- Changes to template_view for both deploying multidisk OVA/vApp as is -DROP VIEW IF EXISTS `cloud`.`template_view`; -CREATE VIEW `cloud`.`template_view` AS - SELECT - `vm_template`.`id` AS `id`, - `vm_template`.`uuid` AS `uuid`, - `vm_template`.`unique_name` AS `unique_name`, - `vm_template`.`name` AS `name`, - `vm_template`.`public` AS `public`, - `vm_template`.`featured` AS `featured`, - `vm_template`.`type` AS `type`, - `vm_template`.`hvm` AS `hvm`, - `vm_template`.`bits` AS `bits`, - `vm_template`.`url` AS `url`, - `vm_template`.`format` AS `format`, - `vm_template`.`created` AS `created`, - `vm_template`.`checksum` AS `checksum`, - `vm_template`.`display_text` AS `display_text`, - `vm_template`.`enable_password` AS `enable_password`, - `vm_template`.`dynamically_scalable` AS `dynamically_scalable`, - `vm_template`.`state` AS `template_state`, - `vm_template`.`guest_os_id` AS `guest_os_id`, - `guest_os`.`uuid` AS `guest_os_uuid`, - `guest_os`.`display_name` AS `guest_os_name`, - `vm_template`.`bootable` AS `bootable`, - `vm_template`.`prepopulate` AS `prepopulate`, - `vm_template`.`cross_zones` AS `cross_zones`, - `vm_template`.`hypervisor_type` AS `hypervisor_type`, - `vm_template`.`extractable` AS `extractable`, - `vm_template`.`template_tag` AS `template_tag`, - `vm_template`.`sort_key` AS `sort_key`, - `vm_template`.`removed` AS `removed`, - `vm_template`.`enable_sshkey` AS `enable_sshkey`, - `parent_template`.`id` AS `parent_template_id`, - `parent_template`.`uuid` AS `parent_template_uuid`, - `source_template`.`id` AS `source_template_id`, - `source_template`.`uuid` AS `source_template_uuid`, - `account`.`id` AS `account_id`, - `account`.`uuid` AS `account_uuid`, - `account`.`account_name` AS `account_name`, - `account`.`type` AS `account_type`, - `domain`.`id` AS `domain_id`, - `domain`.`uuid` AS `domain_uuid`, - `domain`.`name` AS `domain_name`, - `domain`.`path` AS `domain_path`, - `projects`.`id` AS `project_id`, - `projects`.`uuid` AS `project_uuid`, - `projects`.`name` AS `project_name`, - `data_center`.`id` AS `data_center_id`, - `data_center`.`uuid` AS `data_center_uuid`, - `data_center`.`name` AS `data_center_name`, - `launch_permission`.`account_id` AS `lp_account_id`, - `template_store_ref`.`store_id` AS `store_id`, - `image_store`.`scope` AS `store_scope`, - `template_store_ref`.`state` AS `state`, - `template_store_ref`.`download_state` AS `download_state`, - `template_store_ref`.`download_pct` AS `download_pct`, - `template_store_ref`.`error_str` AS `error_str`, - `template_store_ref`.`size` AS `size`, - `template_store_ref`.physical_size AS `physical_size`, - `template_store_ref`.`destroyed` AS `destroyed`, - `template_store_ref`.`created` AS `created_on_store`, - `vm_template_details`.`name` AS `detail_name`, - `vm_template_details`.`value` AS `detail_value`, - `resource_tags`.`id` AS `tag_id`, - `resource_tags`.`uuid` AS `tag_uuid`, - `resource_tags`.`key` AS `tag_key`, - `resource_tags`.`value` AS `tag_value`, - `resource_tags`.`domain_id` AS `tag_domain_id`, - `domain`.`uuid` AS `tag_domain_uuid`, - `domain`.`name` AS `tag_domain_name`, - `resource_tags`.`account_id` AS `tag_account_id`, - `account`.`account_name` AS `tag_account_name`, - `resource_tags`.`resource_id` AS `tag_resource_id`, - `resource_tags`.`resource_uuid` AS `tag_resource_uuid`, - `resource_tags`.`resource_type` AS `tag_resource_type`, - `resource_tags`.`customer` AS `tag_customer`, - CONCAT(`vm_template`.`id`, - '_', - IFNULL(`data_center`.`id`, 0)) AS `temp_zone_pair`, - `vm_template`.`direct_download` AS `direct_download`, - `vm_template`.`deploy_as_is` AS `deploy_as_is` - FROM - (((((((((((((`vm_template` - JOIN `guest_os` ON ((`guest_os`.`id` = `vm_template`.`guest_os_id`))) - JOIN `account` ON ((`account`.`id` = `vm_template`.`account_id`))) - JOIN `domain` ON ((`domain`.`id` = `account`.`domain_id`))) - LEFT JOIN `projects` ON ((`projects`.`project_account_id` = `account`.`id`))) - LEFT JOIN `vm_template_details` ON ((`vm_template_details`.`template_id` = `vm_template`.`id`))) - LEFT JOIN `vm_template` `source_template` ON ((`source_template`.`id` = `vm_template`.`source_template_id`))) - LEFT JOIN `template_store_ref` ON (((`template_store_ref`.`template_id` = `vm_template`.`id`) - AND (`template_store_ref`.`store_role` = 'Image') - AND (`template_store_ref`.`destroyed` = 0)))) - LEFT JOIN `vm_template` `parent_template` ON ((`parent_template`.`id` = `vm_template`.`parent_template_id`))) - LEFT JOIN `image_store` ON ((ISNULL(`image_store`.`removed`) - AND (`template_store_ref`.`store_id` IS NOT NULL) - AND (`image_store`.`id` = `template_store_ref`.`store_id`)))) - LEFT JOIN `template_zone_ref` ON (((`template_zone_ref`.`template_id` = `vm_template`.`id`) - AND ISNULL(`template_store_ref`.`store_id`) - AND ISNULL(`template_zone_ref`.`removed`)))) - LEFT JOIN `data_center` ON (((`image_store`.`data_center_id` = `data_center`.`id`) - OR (`template_zone_ref`.`zone_id` = `data_center`.`id`)))) - LEFT JOIN `launch_permission` ON ((`launch_permission`.`template_id` = `vm_template`.`id`))) - LEFT JOIN `resource_tags` ON (((`resource_tags`.`resource_id` = `vm_template`.`id`) - AND ((`resource_tags`.`resource_type` = 'Template') - OR (`resource_tags`.`resource_type` = 'ISO'))))); - --- Add mincpu, maxcpu, minmemory and maxmemory to the view supporting constrained offerings -DROP VIEW IF EXISTS `cloud`.`service_offering_view`; -CREATE VIEW `cloud`.`service_offering_view` AS - SELECT - `service_offering`.`id` AS `id`, - `disk_offering`.`uuid` AS `uuid`, - `disk_offering`.`name` AS `name`, - `disk_offering`.`display_text` AS `display_text`, - `disk_offering`.`provisioning_type` AS `provisioning_type`, - `disk_offering`.`created` AS `created`, - `disk_offering`.`tags` AS `tags`, - `disk_offering`.`removed` AS `removed`, - `disk_offering`.`use_local_storage` AS `use_local_storage`, - `disk_offering`.`system_use` AS `system_use`, - `disk_offering`.`customized_iops` AS `customized_iops`, - `disk_offering`.`min_iops` AS `min_iops`, - `disk_offering`.`max_iops` AS `max_iops`, - `disk_offering`.`hv_ss_reserve` AS `hv_ss_reserve`, - `disk_offering`.`bytes_read_rate` AS `bytes_read_rate`, - `disk_offering`.`bytes_read_rate_max` AS `bytes_read_rate_max`, - `disk_offering`.`bytes_read_rate_max_length` AS `bytes_read_rate_max_length`, - `disk_offering`.`bytes_write_rate` AS `bytes_write_rate`, - `disk_offering`.`bytes_write_rate_max` AS `bytes_write_rate_max`, - `disk_offering`.`bytes_write_rate_max_length` AS `bytes_write_rate_max_length`, - `disk_offering`.`iops_read_rate` AS `iops_read_rate`, - `disk_offering`.`iops_read_rate_max` AS `iops_read_rate_max`, - `disk_offering`.`iops_read_rate_max_length` AS `iops_read_rate_max_length`, - `disk_offering`.`iops_write_rate` AS `iops_write_rate`, - `disk_offering`.`iops_write_rate_max` AS `iops_write_rate_max`, - `disk_offering`.`iops_write_rate_max_length` AS `iops_write_rate_max_length`, - `disk_offering`.`cache_mode` AS `cache_mode`, - `disk_offering`.`disk_size` AS `root_disk_size`, - `service_offering`.`cpu` AS `cpu`, - `service_offering`.`speed` AS `speed`, - `service_offering`.`ram_size` AS `ram_size`, - `service_offering`.`nw_rate` AS `nw_rate`, - `service_offering`.`mc_rate` AS `mc_rate`, - `service_offering`.`ha_enabled` AS `ha_enabled`, - `service_offering`.`limit_cpu_use` AS `limit_cpu_use`, - `service_offering`.`host_tag` AS `host_tag`, - `service_offering`.`default_use` AS `default_use`, - `service_offering`.`vm_type` AS `vm_type`, - `service_offering`.`sort_key` AS `sort_key`, - `service_offering`.`is_volatile` AS `is_volatile`, - `service_offering`.`deployment_planner` AS `deployment_planner`, - `vsphere_storage_policy`.`value` AS `vsphere_storage_policy`, - GROUP_CONCAT(DISTINCT(domain.id)) AS domain_id, - GROUP_CONCAT(DISTINCT(domain.uuid)) AS domain_uuid, - GROUP_CONCAT(DISTINCT(domain.name)) AS domain_name, - GROUP_CONCAT(DISTINCT(domain.path)) AS domain_path, - GROUP_CONCAT(DISTINCT(zone.id)) AS zone_id, - GROUP_CONCAT(DISTINCT(zone.uuid)) AS zone_uuid, - GROUP_CONCAT(DISTINCT(zone.name)) AS zone_name, - IFNULL(`min_compute_details`.`value`, `cpu`) AS min_cpu, - IFNULL(`max_compute_details`.`value`, `cpu`) AS max_cpu, - IFNULL(`min_memory_details`.`value`, `ram_size`) AS min_memory, - IFNULL(`max_memory_details`.`value`, `ram_size`) AS max_memory - FROM - `cloud`.`service_offering` - INNER JOIN - `cloud`.`disk_offering_view` AS `disk_offering` ON service_offering.id = disk_offering.id - LEFT JOIN - `cloud`.`service_offering_details` AS `domain_details` ON `domain_details`.`service_offering_id` = `disk_offering`.`id` AND `domain_details`.`name`='domainid' - LEFT JOIN - `cloud`.`domain` AS `domain` ON FIND_IN_SET(`domain`.`id`, `domain_details`.`value`) - LEFT JOIN - `cloud`.`service_offering_details` AS `zone_details` ON `zone_details`.`service_offering_id` = `disk_offering`.`id` AND `zone_details`.`name`='zoneid' - LEFT JOIN - `cloud`.`data_center` AS `zone` ON FIND_IN_SET(`zone`.`id`, `zone_details`.`value`) - LEFT JOIN - `cloud`.`service_offering_details` AS `min_compute_details` ON `min_compute_details`.`service_offering_id` = `disk_offering`.`id` - AND `min_compute_details`.`name` = 'mincpunumber' - LEFT JOIN - `cloud`.`service_offering_details` AS `max_compute_details` ON `max_compute_details`.`service_offering_id` = `disk_offering`.`id` - AND `max_compute_details`.`name` = 'maxcpunumber' - LEFT JOIN - `cloud`.`service_offering_details` AS `min_memory_details` ON `min_memory_details`.`service_offering_id` = `disk_offering`.`id` - AND `min_memory_details`.`name` = 'minmemory' - LEFT JOIN - `cloud`.`service_offering_details` AS `max_memory_details` ON `max_memory_details`.`service_offering_id` = `disk_offering`.`id` - AND `max_memory_details`.`name` = 'maxmemory' - LEFT JOIN - `cloud`.`service_offering_details` AS `vsphere_storage_policy` ON `vsphere_storage_policy`.`service_offering_id` = `disk_offering`.`id` - AND `vsphere_storage_policy`.`name` = 'storagepolicy' - WHERE - `disk_offering`.`state`='Active' - GROUP BY - `service_offering`.`id`; - -DROP VIEW IF EXISTS `cloud`.`disk_offering_view`; -CREATE VIEW `cloud`.`disk_offering_view` AS +-- Network offering with multi-domains and multi-zones +DROP VIEW IF EXISTS `cloud`.`network_offering_view`; +CREATE VIEW `cloud`.`network_offering_view` AS SELECT - `disk_offering`.`id` AS `id`, - `disk_offering`.`uuid` AS `uuid`, - `disk_offering`.`name` AS `name`, - `disk_offering`.`display_text` AS `display_text`, - `disk_offering`.`provisioning_type` AS `provisioning_type`, - `disk_offering`.`disk_size` AS `disk_size`, - `disk_offering`.`min_iops` AS `min_iops`, - `disk_offering`.`max_iops` AS `max_iops`, - `disk_offering`.`created` AS `created`, - `disk_offering`.`tags` AS `tags`, - `disk_offering`.`customized` AS `customized`, - `disk_offering`.`customized_iops` AS `customized_iops`, - `disk_offering`.`removed` AS `removed`, - `disk_offering`.`use_local_storage` AS `use_local_storage`, - `disk_offering`.`system_use` AS `system_use`, - `disk_offering`.`hv_ss_reserve` AS `hv_ss_reserve`, - `disk_offering`.`bytes_read_rate` AS `bytes_read_rate`, - `disk_offering`.`bytes_read_rate_max` AS `bytes_read_rate_max`, - `disk_offering`.`bytes_read_rate_max_length` AS `bytes_read_rate_max_length`, - `disk_offering`.`bytes_write_rate` AS `bytes_write_rate`, - `disk_offering`.`bytes_write_rate_max` AS `bytes_write_rate_max`, - `disk_offering`.`bytes_write_rate_max_length` AS `bytes_write_rate_max_length`, - `disk_offering`.`iops_read_rate` AS `iops_read_rate`, - `disk_offering`.`iops_read_rate_max` AS `iops_read_rate_max`, - `disk_offering`.`iops_read_rate_max_length` AS `iops_read_rate_max_length`, - `disk_offering`.`iops_write_rate` AS `iops_write_rate`, - `disk_offering`.`iops_write_rate_max` AS `iops_write_rate_max`, - `disk_offering`.`iops_write_rate_max_length` AS `iops_write_rate_max_length`, - `disk_offering`.`cache_mode` AS `cache_mode`, - `disk_offering`.`sort_key` AS `sort_key`, - `disk_offering`.`type` AS `type`, - `disk_offering`.`display_offering` AS `display_offering`, - `disk_offering`.`state` AS `state`, - `vsphere_storage_policy`.`value` AS `vsphere_storage_policy`, + `network_offerings`.`id` AS `id`, + `network_offerings`.`uuid` AS `uuid`, + `network_offerings`.`name` AS `name`, + `network_offerings`.`unique_name` AS `unique_name`, + `network_offerings`.`display_text` AS `display_text`, + `network_offerings`.`nw_rate` AS `nw_rate`, + `network_offerings`.`mc_rate` AS `mc_rate`, + `network_offerings`.`traffic_type` AS `traffic_type`, + `network_offerings`.`tags` AS `tags`, + `network_offerings`.`system_only` AS `system_only`, + `network_offerings`.`specify_vlan` AS `specify_vlan`, + `network_offerings`.`service_offering_id` AS `service_offering_id`, + `network_offerings`.`conserve_mode` AS `conserve_mode`, + `network_offerings`.`created` AS `created`, + `network_offerings`.`removed` AS `removed`, + `network_offerings`.`default` AS `default`, + `network_offerings`.`availability` AS `availability`, + `network_offerings`.`dedicated_lb_service` AS `dedicated_lb_service`, + `network_offerings`.`shared_source_nat_service` AS `shared_source_nat_service`, + `network_offerings`.`sort_key` AS `sort_key`, + `network_offerings`.`redundant_router_service` AS `redundant_router_service`, + `network_offerings`.`state` AS `state`, + `network_offerings`.`guest_type` AS `guest_type`, + `network_offerings`.`elastic_ip_service` AS `elastic_ip_service`, + `network_offerings`.`eip_associate_public_ip` AS `eip_associate_public_ip`, + `network_offerings`.`elastic_lb_service` AS `elastic_lb_service`, + `network_offerings`.`specify_ip_ranges` AS `specify_ip_ranges`, + `network_offerings`.`inline` AS `inline`, + `network_offerings`.`is_persistent` AS `is_persistent`, + `network_offerings`.`internal_lb` AS `internal_lb`, + `network_offerings`.`public_lb` AS `public_lb`, + `network_offerings`.`egress_default_policy` AS `egress_default_policy`, + `network_offerings`.`concurrent_connections` AS `concurrent_connections`, + `network_offerings`.`keep_alive_enabled` AS `keep_alive_enabled`, + `network_offerings`.`supports_streched_l2` AS `supports_streched_l2`, + `network_offerings`.`supports_public_access` AS `supports_public_access`, + `network_offerings`.`for_vpc` AS `for_vpc`, + `network_offerings`.`for_tungsten` AS `for_tungsten`, + `network_offerings`.`service_package_id` AS `service_package_id`, GROUP_CONCAT(DISTINCT(domain.id)) AS domain_id, GROUP_CONCAT(DISTINCT(domain.uuid)) AS domain_uuid, GROUP_CONCAT(DISTINCT(domain.name)) AS domain_name, @@ -509,94 +72,14 @@ CREATE VIEW `cloud`.`disk_offering_view` AS GROUP_CONCAT(DISTINCT(zone.uuid)) AS zone_uuid, GROUP_CONCAT(DISTINCT(zone.name)) AS zone_name FROM - `cloud`.`disk_offering` + `cloud`.`network_offerings` LEFT JOIN - `cloud`.`disk_offering_details` AS `domain_details` ON `domain_details`.`offering_id` = `disk_offering`.`id` AND `domain_details`.`name`='domainid' + `cloud`.`network_offering_details` AS `domain_details` ON `domain_details`.`network_offering_id` = `network_offerings`.`id` AND `domain_details`.`name`='domainid' LEFT JOIN `cloud`.`domain` AS `domain` ON FIND_IN_SET(`domain`.`id`, `domain_details`.`value`) LEFT JOIN - `cloud`.`disk_offering_details` AS `zone_details` ON `zone_details`.`offering_id` = `disk_offering`.`id` AND `zone_details`.`name`='zoneid' + `cloud`.`network_offering_details` AS `zone_details` ON `zone_details`.`network_offering_id` = `network_offerings`.`id` AND `zone_details`.`name`='zoneid' LEFT JOIN `cloud`.`data_center` AS `zone` ON FIND_IN_SET(`zone`.`id`, `zone_details`.`value`) - LEFT JOIN - `cloud`.`disk_offering_details` AS `vsphere_storage_policy` ON `vsphere_storage_policy`.`offering_id` = `disk_offering`.`id` - AND `vsphere_storage_policy`.`name` = 'storagepolicy' - - WHERE - `disk_offering`.`state`='Active' GROUP BY - `disk_offering`.`id`; - -ALTER TABLE `cloud`.`template_spool_ref` -DROP FOREIGN KEY `fk_template_spool_ref__template_id`; - -ALTER TABLE `cloud`.`template_spool_ref` -ADD COLUMN `deployment_option` VARCHAR(255) NULL DEFAULT NULL AFTER `updated`, -ADD INDEX `fk_template_spool_ref__template_id_idx` (`template_id` ASC), -ADD UNIQUE INDEX `index_template_spool_configuration` (`pool_id` ASC, `template_id` ASC, `deployment_option` ASC), -DROP INDEX `i_template_spool_ref__template_id__pool_id` ; - -ALTER TABLE `cloud`.`template_spool_ref` -ADD CONSTRAINT `fk_template_spool_ref__template_id` - FOREIGN KEY (`template_id`) - REFERENCES `cloud`.`vm_template` (`id`) - ON DELETE NO ACTION - ON UPDATE NO ACTION; - -CREATE TABLE `cloud`.`template_deploy_as_is_details` ( - `id` bigint unsigned NOT NULL auto_increment, - `template_id` bigint unsigned NOT NULL COMMENT 'template id', - `name` varchar(255) NOT NULL, - `value` TEXT, - PRIMARY KEY (`id`), - CONSTRAINT `fk_template_deploy_as_is_details__template_id` FOREIGN KEY `fk_template_deploy_as_is_details__template_id`(`template_id`) REFERENCES `vm_template`(`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -CREATE TABLE `cloud`.`user_vm_deploy_as_is_details` ( - `id` bigint unsigned NOT NULL auto_increment, - `vm_id` bigint unsigned NOT NULL COMMENT 'virtual machine id', - `name` varchar(255) NOT NULL, - `value` TEXT, - PRIMARY KEY (`id`), - CONSTRAINT `fk_user_vm_deploy_as_is_details__vm_id` FOREIGN KEY `fk_user_vm_deploy_as_is_details__vm_id`(`vm_id`) REFERENCES `vm_instance`(`id`) ON DELETE CASCADE -) ENGINE=InnoDB DEFAULT CHARSET=utf8; - -ALTER TABLE `cloud`.`image_store` ADD COLUMN `readonly` boolean DEFAULT false COMMENT 'defines status of image store'; - -DROP VIEW IF EXISTS `cloud`.`image_store_view`; -CREATE VIEW `cloud`.`image_store_view` AS - select - image_store.id, - image_store.uuid, - image_store.name, - image_store.image_provider_name, - image_store.protocol, - image_store.url, - image_store.scope, - image_store.role, - image_store.readonly, - image_store.removed, - data_center.id data_center_id, - data_center.uuid data_center_uuid, - data_center.name data_center_name, - image_store_details.name detail_name, - image_store_details.value detail_value - from - `cloud`.`image_store` - left join - `cloud`.`data_center` ON image_store.data_center_id = data_center.id - left join - `cloud`.`image_store_details` ON image_store_details.store_id = image_store.id; - --- Fix OS category for Guest OS 'Other PV Virtio-SCSI (64-bit)' -UPDATE `cloud`.`guest_os` SET category_id = 7 WHERE id = 275 AND display_name = 'Other PV Virtio-SCSI (64-bit)'; - --- Add flag 'hidden' in tables usage_ip_address and cloud_usage -ALTER TABLE `cloud_usage`.`usage_ip_address` ADD COLUMN `is_hidden` smallint(1) NOT NULL DEFAULT '0' COMMENT 'is usage hidden'; -ALTER TABLE `cloud_usage`.`cloud_usage` ADD COLUMN `is_hidden` smallint(1) NOT NULL DEFAULT '0' COMMENT 'is usage hidden'; - --- Fix Zones are returned in a random order (#3934) -UPDATE `cloud`.`data_center` JOIN (SELECT COUNT(1) AS count FROM `cloud`.`data_center` WHERE `sort_key` != 0) AS tbl_tmp SET `sort_key` = `id` WHERE count = 0; - --- Fix description of volume.stats.interval which is in milliseconds not seconds -UPDATE `cloud`.`configuration` SET `description` = 'Interval (in milliseconds) to report volume statistics' WHERE `name` = 'volume.stats.interval'; + `network_offerings`.`id`; \ No newline at end of file diff --git a/plugins/network-elements/dns-notifier/src/main/resources/components-example.xml b/plugins/network-elements/dns-notifier/src/main/resources/components-example.xml index 9d1b1200776a..7a293cdbd204 100755 --- a/plugins/network-elements/dns-notifier/src/main/resources/components-example.xml +++ b/plugins/network-elements/dns-notifier/src/main/resources/components-example.xml @@ -30,7 +30,7 @@ under the License. - true + true @@ -75,6 +75,7 @@ under the License. + @@ -96,7 +97,7 @@ under the License. - + @@ -112,7 +113,7 @@ under the License. - + @@ -137,6 +138,7 @@ under the License. + @@ -166,10 +168,10 @@ under the License. - true + true - + @@ -177,7 +179,7 @@ under the License. - + diff --git a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java index 1a92945131d0..ad0262840758 100644 --- a/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java +++ b/plugins/network-elements/juniper-contrail/src/main/java/org/apache/cloudstack/network/contrail/management/ContrailManagerImpl.java @@ -34,12 +34,21 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import net.juniper.contrail.api.ApiConnector; +import net.juniper.contrail.api.ApiConnectorFactory; +import net.juniper.contrail.api.ApiPropertyBase; +import net.juniper.contrail.api.ObjectReference; +import net.juniper.contrail.api.types.FloatingIp; +import net.juniper.contrail.api.types.FloatingIpPool; +import net.juniper.contrail.api.types.NetworkPolicy; +import net.juniper.contrail.api.types.VirtualNetwork; + import org.apache.cloudstack.network.contrail.model.FloatingIpModel; import org.apache.cloudstack.network.contrail.model.FloatingIpPoolModel; import org.apache.cloudstack.network.contrail.model.ModelController; import org.apache.cloudstack.network.contrail.model.VirtualNetworkModel; import org.apache.commons.io.IOUtils; -import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang.StringUtils; import org.apache.log4j.Logger; import com.cloud.configuration.ConfigurationManager; @@ -90,15 +99,6 @@ import com.cloud.vm.dao.VMInstanceDao; import com.google.common.collect.ImmutableList; -import net.juniper.contrail.api.ApiConnector; -import net.juniper.contrail.api.ApiConnectorFactory; -import net.juniper.contrail.api.ApiPropertyBase; -import net.juniper.contrail.api.ObjectReference; -import net.juniper.contrail.api.types.FloatingIp; -import net.juniper.contrail.api.types.FloatingIpPool; -import net.juniper.contrail.api.types.NetworkPolicy; -import net.juniper.contrail.api.types.VirtualNetwork; - public class ContrailManagerImpl extends ManagerBase implements ContrailManager { @Inject public ConfigurationService _configService; @@ -193,7 +193,7 @@ public ModelDatabase getDatabase() { } private NetworkOffering locatePublicNetworkOffering(String offeringName, - String offeringDisplayText, Provider provider) { + String offeringDisplayText, Provider provider) { List offerList = _configService.listNetworkOfferings(TrafficType.Public, false); for (NetworkOffering offer: offerList) { if (offer.getName().equals(offeringName)) { @@ -219,14 +219,16 @@ private NetworkOffering locatePublicNetworkOffering(String offeringName, ConfigurationManager configMgr = (ConfigurationManager) _configService; NetworkOfferingVO voffer = configMgr.createNetworkOffering(offeringName, offeringDisplayText, TrafficType.Public, null, true, Availability.Optional, null, serviceProviderMap, true, - Network.GuestType.Shared, false, null, false, null, true, false, null, true, null, false, false, null, null, true, null); + Network.GuestType.Shared, false, null, false, null, true, false, null, true, null, false, false, false,null, null); + + voffer.setState(NetworkOffering.State.Enabled); long id = voffer.getId(); _networkOfferingDao.update(id, voffer); return _networkOfferingDao.findById(id); } private NetworkOffering locateNetworkOffering(String offeringName, - String offeringDisplayText, Provider provider) { + String offeringDisplayText, Provider provider) { List offerList = _configService.listNetworkOfferings(TrafficType.Guest, false); for (NetworkOffering offer : offerList) { if (offer.getName().equals(offeringName)) { @@ -254,7 +256,9 @@ private NetworkOffering locateNetworkOffering(String offeringName, ConfigurationManager configMgr = (ConfigurationManager)_configService; NetworkOfferingVO voffer = configMgr.createNetworkOffering(offeringName, offeringDisplayText, TrafficType.Guest, null, false, Availability.Optional, null, serviceProviderMap, true, - Network.GuestType.Isolated, false, null, false, null, false, true, null, true, null, false, offeringName.equals(vpcRouterOfferingName), null, null, true, null); + Network.GuestType.Isolated, false, null, false, null, false, true, null, true, null, false, offeringName.equals(vpcRouterOfferingName), false,null, null); + + voffer.setState(NetworkOffering.State.Enabled); if (offeringName.equals(vpcRouterOfferingName)) { voffer.setInternalLb(true); } @@ -295,7 +299,8 @@ private VpcOffering locateVpcOffering() { } serviceProviderMap.put(svc, providerSet); } - vpcOffer = _vpcProvSvc.createVpcOffering(juniperVPCOfferingName, juniperVPCOfferingDisplayText, services, serviceProviderMap, null, null, null, null, null, VpcOffering.State.Enabled); + vpcOffer = _vpcProvSvc.createVpcOffering(juniperVPCOfferingName, juniperVPCOfferingDisplayText, services, serviceProviderMap, null, null, null, null); + ((VpcOfferingVO)vpcOffer).setState(VpcOffering.State.Enabled); long id = vpcOffer.getId(); _vpcOffDao.update(id, (VpcOfferingVO)vpcOffer); return _vpcOffDao.findById(id); @@ -438,7 +443,7 @@ public String getDomainName(long domainId) { @Override public String getProjectName(long accountId) { Account account = _accountDao.findById(accountId); - if (account.getType() == Account.Type.PROJECT) { + if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) { ProjectVO project = _projectDao.findByProjectAccountId(account.getId()); if (project != null) { return project.getName(); @@ -455,7 +460,7 @@ public String getDefaultPublicNetworkFQN() { private ProjectVO getProject(long accountId) { Account account = _accountDao.findById(accountId); - if (account.getType() == Account.Type.PROJECT) { + if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) { return _projectDao.findByProjectAccountId(account.getId()); } return null; diff --git a/plugins/network-elements/stratosphere-ssp/src/main/java/org/apache/cloudstack/network/guru/SspGuestNetworkGuru.java b/plugins/network-elements/stratosphere-ssp/src/main/java/org/apache/cloudstack/network/guru/SspGuestNetworkGuru.java index 9ede8cc5a3e6..ac7b24043956 100644 --- a/plugins/network-elements/stratosphere-ssp/src/main/java/org/apache/cloudstack/network/guru/SspGuestNetworkGuru.java +++ b/plugins/network-elements/stratosphere-ssp/src/main/java/org/apache/cloudstack/network/guru/SspGuestNetworkGuru.java @@ -77,6 +77,8 @@ protected boolean canHandle(NetworkOffering offering, NetworkType networkType, P s_logger.info("SSP works for network isolatation."); } else if (!_sspMgr.canHandle(physicalNetwork)) { s_logger.info("SSP manager not ready"); + } else if(offering.isForTungsten()){ + s_logger.info("This offering is for Tungsten SDN"); } else { return true; } @@ -95,7 +97,7 @@ protected boolean canHandle(NetworkOffering offering, NetworkType networkType, P */ @Override public Network implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) - throws InsufficientVirtualNetworkCapacityException { + throws InsufficientVirtualNetworkCapacityException { s_logger.trace("implement " + network.toString()); super.implement(network, offering, dest, context); _sspMgr.createNetwork(network, offering, dest, context); @@ -111,7 +113,7 @@ public void shutdown(NetworkProfile profile, NetworkOffering offering) { @Override public void reserve(NicProfile nic, Network network, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) - throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { super.reserve(nic, network, vm, dest, context); _sspMgr.createNicEnv(network, nic, dest, context); } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenNetworkCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenNetworkCmd.java index 32cae841e624..34bd66e95810 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenNetworkCmd.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenNetworkCmd.java @@ -47,6 +47,9 @@ public class CreateTungstenNetworkCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Tungsten network Name") private String name; + @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_UUID, type = CommandType.STRING, description = "Tungsten network uuid. If null tungsten will generate an uuid for the network") + private String tungstenNetworkUuid; + @Parameter(name = ApiConstants.TUNGSTEN_NETWORK_IPAM_UUID, type = CommandType.STRING, description = "Network Ipam UUID") private String networkIpamUUID; @@ -82,6 +85,10 @@ public String getName() { return name; } + public String getTungstenNetworkUuid() { + return tungstenNetworkUuid; + } + public String getNetworkIpamUUID() { return networkIpamUUID; } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenVirtualMachineCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenVirtualMachineCmd.java index facfe9c79007..681f9604402a 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenVirtualMachineCmd.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenVirtualMachineCmd.java @@ -46,10 +46,17 @@ public class CreateTungstenVirtualMachineCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Tungsten virtual machine interface name") private String name; + @Parameter(name = ApiConstants.TUNGSTEN_VIRTUAL_MACHINE_UUID, type = CommandType.STRING, description = "Tungsten virtual machine uuid. If null tungsten will generate an uuid for the virtual machine") + private String tungstenVmUuid; + public String getName() { return name; } + public String getTungstenVmUuid() { + return tungstenVmUuid; + } + @Inject TungstenManager tungstenManager; diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenNetworkCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenNetworkCmd.java index b60742f7632e..e26aace08882 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenNetworkCmd.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenNetworkCmd.java @@ -26,11 +26,11 @@ public class DeleteTungstenNetworkCmd extends BaseCmd { private static final String s_name = "deletetungstennetworkresponse"; - @Parameter(name= ApiConstants.UUID, type=CommandType.STRING, required=true, description="The UUID of the tungsten network") - private String uuid; + @Parameter(name= ApiConstants.TUNGSTEN_NETWORK_UUID, type=CommandType.STRING, required=true, description="The UUID of the tungsten network") + private String tungstenNetworkUuid; - public String getUuid() { - return uuid; + public String getTungstenNetworkUuid() { + return tungstenNetworkUuid; } @Inject diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenVirtualRouterCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenVirtualRouterCmd.java new file mode 100644 index 000000000000..ef8765c39025 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenVirtualRouterCmd.java @@ -0,0 +1,55 @@ +package org.apache.cloudstack.network.tungsten.api.command; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseListTaggedResourcesCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.command.user.UserCmd; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.network.tungsten.api.response.TungstenVirtualRouterResponse; +import org.apache.cloudstack.network.tungsten.service.TungstenManager; + +import javax.inject.Inject; +import java.io.IOException; + +@APICommand(name = "listTungstenVirtualRouters", + description = "List tungsten virtual routers", + responseObject = TungstenVirtualRouterResponse.class) +public class ListTungstenVirtualRouterCmd extends BaseListTaggedResourcesCmd implements UserCmd { + + private static final String s_name = "listtungstenvirtualroutersresponse"; + + @Parameter(name = ApiConstants.TUNGSTEN_VIRTUAL_ROUTER_UUID, type = CommandType.STRING, description = "list tungsten virtual routers by uuid") + private String virtualRouterUuid; + + public String getVirtualRouterUuid() { + return virtualRouterUuid; + } + + @Inject + TungstenManager tungstenManager; + + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try{ + ListResponse response = tungstenManager.getVirtualRouters(this); + response.setResponseName(getCommandName()); + setResponseObject(response); + } catch (IOException e) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to retrieve virtual routers from tungsten."); + } + } + + @Override + public String getCommandName() { + return s_name; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenVirtualRouterResponse.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenVirtualRouterResponse.java new file mode 100644 index 000000000000..3158fee9bae7 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenVirtualRouterResponse.java @@ -0,0 +1,32 @@ +package org.apache.cloudstack.network.tungsten.api.response; + +import com.cloud.serializer.Param; +import com.google.gson.annotations.SerializedName; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseResponse; + +public class TungstenVirtualRouterResponse extends BaseResponse { + + @SerializedName(ApiConstants.UUID) + @Param(description = "UUID of the tungsten virtual machine") + private String uuid; + @SerializedName(ApiConstants.NAME) + @Param(description = "name of the tungsten virtual machine") + private String name; + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java new file mode 100644 index 000000000000..08c908c17392 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java @@ -0,0 +1,133 @@ +package org.apache.cloudstack.network.tungsten.service; + +import com.cloud.deploy.DeployDestination; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.Network; +import com.cloud.network.NetworkModel; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.PublicIpAddress; +import com.cloud.network.element.IpDeployer; +import com.cloud.network.element.StaticNatServiceProvider; +import com.cloud.network.rules.StaticNat; +import com.cloud.offering.NetworkOffering; +import com.cloud.utils.component.AdapterBase; +import com.cloud.vm.NicProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VirtualMachineProfile; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.inject.Inject; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +@Component +public class TungstenElement extends AdapterBase implements StaticNatServiceProvider, IpDeployer { + + @Inject + NetworkModel _networkModel; + @Inject + TungstenService _tungstenService; + + private static final Logger s_logger = Logger.getLogger(TungstenElement.class); + private final Map> _capabilities = InitCapabilities(); + + protected boolean canHandle(final Network network, final Network.Service service) { + s_logger.debug("Checking if OvsElement can handle service " + + service.getName() + " on network " + network.getDisplayText()); + + if (!_networkModel.isProviderForNetwork(getProvider(), network.getId())) { + s_logger.debug("OvsElement is not a provider for network " + + network.getDisplayText()); + return false; + } + + return true; + } + + @Override + public boolean applyStaticNats(Network config, List rules) throws ResourceUnavailableException { + return false; + } + + @Override + public IpDeployer getIpDeployer(Network network) { + return this; + } + + @Override + public Map> getCapabilities() { + return _capabilities; + } + + private static Map> InitCapabilities() { + Map> capabilities = new HashMap>(); + capabilities.put(Network.Service.Dhcp, new HashMap()); + Map sourceNatCapabilities = new HashMap(); + sourceNatCapabilities.put(Network.Capability.SupportedSourceNatTypes, "peraccount"); + capabilities.put(Network.Service.SourceNat, sourceNatCapabilities); + return capabilities; + } + + @Override + public boolean applyIps(Network network, List ipAddress, Set services) throws ResourceUnavailableException { + return true; + } + + @Override + public Network.Provider getProvider() { + return Network.Provider.Tungsten; + } + + @Override + public boolean implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + return true; + } + + @Override + public boolean prepare(Network network, NicProfile nic, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException, InsufficientCapacityException { + return false; + } + + @Override + public boolean release(Network network, NicProfile nic, VirtualMachineProfile vm, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + return false; + } + + @Override + public boolean shutdown(Network network, ReservationContext context, boolean cleanup) throws ConcurrentOperationException, ResourceUnavailableException { + if (!canHandle(network, Network.Service.Connectivity)) { + return false; + } + return true; + } + + @Override + public boolean destroy(Network network, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + return true; + } + + @Override + public boolean isReady(PhysicalNetworkServiceProvider provider) { + return true; + } + + @Override + public boolean shutdownProviderInstances(PhysicalNetworkServiceProvider provider, ReservationContext context) throws ConcurrentOperationException, ResourceUnavailableException { + return false; + } + + @Override + public boolean canEnableIndividualServices() { + return true; + } + + @Override + public boolean verifyServicesCombination(Set services) { + return true; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java new file mode 100644 index 000000000000..721a4363a3d1 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java @@ -0,0 +1,181 @@ +package org.apache.cloudstack.network.tungsten.service; + +import com.cloud.dc.DataCenter; +import com.cloud.deploy.DeployDestination; +import com.cloud.deploy.DeploymentPlan; +import com.cloud.exception.InsufficientAddressCapacityException; +import com.cloud.exception.InsufficientVirtualNetworkCapacityException; +import com.cloud.network.Network; +import com.cloud.network.Networks; +import com.cloud.network.PhysicalNetwork; +import com.cloud.network.dao.NetworkVO; +import com.cloud.network.dao.PhysicalNetworkVO; +import com.cloud.network.guru.GuestNetworkGuru; +import com.cloud.network.guru.NetworkGuruTungsten; +import com.cloud.offering.NetworkOffering; +import com.cloud.user.Account; +import com.cloud.utils.db.DB; +import com.cloud.utils.exception.CloudRuntimeException; +import com.cloud.vm.Nic; +import com.cloud.vm.NicProfile; +import com.cloud.vm.ReservationContext; +import com.cloud.vm.VirtualMachineProfile; +import net.juniper.contrail.api.types.VirtualMachine; +import net.juniper.contrail.api.types.VirtualMachineInterface; +import net.juniper.contrail.api.types.VirtualNetwork; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.inject.Inject; +import java.io.IOException; +import java.util.Arrays; +import java.util.List; + +@Component +public class TungstenGuestNetworkGuru extends GuestNetworkGuru implements NetworkGuruTungsten { + + private static final Logger s_logger = Logger + .getLogger(TungstenGuestNetworkGuru.class); + + @Inject + TungstenService tungstenService; + + @Override + protected boolean canHandle(NetworkOffering offering, DataCenter.NetworkType networkType, PhysicalNetwork physicalNetwork) { + return offering.isForTungsten(); + } + + @Override + public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { + + PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan.getPhysicalNetworkId()); + DataCenter dc = _dcDao.findById(plan.getDataCenterId()); + + if(!canHandle(offering, dc.getNetworkType(),physnet)){ + s_logger.debug("Refusing to design this network"); + return null; + } + + NetworkVO network = (NetworkVO)super.design(offering, plan, userSpecified, owner); + + return network; + } + + @Override + public NicProfile allocate(Network config, NicProfile nic, VirtualMachineProfile vm) throws InsufficientVirtualNetworkCapacityException, + InsufficientAddressCapacityException { + + if (_networkModel.networkIsConfiguredForExternalNetworking(config.getDataCenterId(), config.getId()) && nic != null && nic.getRequestedIPv4() != null) { + throw new CloudRuntimeException("Does not support custom ip allocation at this time: " + nic); + } + + NicProfile profile = super.allocate(config, nic, vm); + + if (_networkModel.networkIsConfiguredForExternalNetworking(config.getDataCenterId(), config.getId())) { + profile.setReservationStrategy(Nic.ReservationStrategy.Start); + /* We won't clear IP address, because router may set gateway as it IP, and it would be updated properly later */ + //profile.setIp4Address(null); + profile.setIPv4Gateway(null); + profile.setIPv4Netmask(null); + } + + return profile; + } + + @Override + @DB + public void deallocate(Network config, NicProfile nic, VirtualMachineProfile vm) { + super.deallocate(config, nic, vm); + + if (_networkModel.networkIsConfiguredForExternalNetworking(config.getDataCenterId(), config.getId())) { + nic.setIPv4Address(null); + nic.setIPv4Gateway(null); + nic.setIPv4Netmask(null); + nic.setBroadcastUri(null); + nic.setIsolationUri(null); + } + try { + tungstenService.expugeVmFromTungsten(vm.getUuid()); + } catch (IOException e) { + throw new CloudRuntimeException("Failing to expuge the vm from tungsten with the uuid " + vm.getUuid()); + } + } + + @Override + public Network implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws InsufficientVirtualNetworkCapacityException { + + assert (network.getState() == Network.State.Implementing) : "Why are we implementing " + + network; + + long dcId = dest.getDataCenter().getId(); + DataCenter.NetworkType nwType = dest.getDataCenter().getNetworkType(); + // get physical network id + Long physicalNetworkId = network.getPhysicalNetworkId(); + // physical network id can be null in Guest Network in Basic zone, so + // locate the physical network + if (physicalNetworkId == null) { + physicalNetworkId = _networkModel.findPhysicalNetworkId(dcId, + offering.getTags(), offering.getTrafficType()); + } + PhysicalNetworkVO physnet = _physicalNetworkDao + .findById(physicalNetworkId); + + if (!canHandle(offering, nwType, physnet)) { + s_logger.debug("Refusing to implement this network"); + return null; + } + NetworkVO implemented = (NetworkVO)super.implement(network, offering, + dest, context); + + if (network.getGateway() != null) { + implemented.setGateway(network.getGateway()); + } + + if (network.getCidr() != null) { + implemented.setCidr(network.getCidr()); + } + + implemented.setBroadcastDomainType(Networks.BroadcastDomainType.Vxlan); + + return implemented; + } + + @Override + public boolean trash(Network network, NetworkOffering offering) { + try { + tungstenService.deleteNetworkFromTungsten(network.getTungstenNetworkUuid()); + } catch (IOException e) { + return false; + } + return super.trash(network, offering); + } + + @Override + public Network createNetworkInTungsten(Network networkVO) { + List subnetIp = Arrays.asList(networkVO.getCidr().split("/")); + String subnetIpPrefix = subnetIp.get(0); + int subnetIpPrefixLength = Integer.parseInt(subnetIp.get(1)); + boolean isDhcpEnabled = networkVO.getMode().equals(Networks.Mode.Dhcp); + VirtualNetwork virtualNetwork = tungstenService.createNetworkInTungsten(null, networkVO.getName(), null, + null, null, subnetIpPrefix, subnetIpPrefixLength, networkVO.getGateway(), isDhcpEnabled, null, false); + networkVO.setTungstenNetworkUuid(virtualNetwork.getUuid()); + return networkVO; + } + + @Override + public String createVirtualMachineInTungsten(String virtualMachineUuid, String virtualMachineName) { + VirtualMachine virtualMachine = tungstenService.createVmInTungsten(virtualMachineUuid, virtualMachineName); + return virtualMachine.getUuid(); + } + + @Override + public String createVmInterfaceInTungsten(String vmInterfaceName, String tungstenProjectUuid, String tungstenNetworkUuid, String tungstenVirtualMachineUuid, String tungstenSecurityGroupUuid, List tungstenVmInterfaceMacAddresses) { + VirtualMachineInterface virtualMachineInterface = tungstenService.createVmInterfaceInTungsten(vmInterfaceName + "-Interface", tungstenProjectUuid, tungstenNetworkUuid, tungstenVirtualMachineUuid, tungstenSecurityGroupUuid, tungstenVmInterfaceMacAddresses); + return virtualMachineInterface.getUuid(); + } + + @Override + public void createTungstenInstanceIp(String instanceIpName, String tungstenVmInterfaceUuid, String tungstenNetworkUuid, String tungstenInstanceIpAddress) { + tungstenService.createInstanceIpInTungsten(instanceIpName, tungstenVmInterfaceUuid, tungstenNetworkUuid, tungstenInstanceIpAddress); + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java index 33695d97c5a8..9555329cb72d 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java @@ -17,9 +17,11 @@ import org.apache.cloudstack.network.tungsten.api.command.DeleteVRouterPortCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenNetworkCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVirtualMachineCmd; +import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVirtualRouterCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVmInterfaceCmd; import org.apache.cloudstack.network.tungsten.api.response.TungstenNetworkResponse; import org.apache.cloudstack.network.tungsten.api.response.TungstenVirtualMachineResponse; +import org.apache.cloudstack.network.tungsten.api.response.TungstenVirtualRouterResponse; import org.apache.cloudstack.network.tungsten.api.response.TungstenVmInterfaceResponse; import java.io.IOException; @@ -28,10 +30,10 @@ public interface TungstenManager extends PluggableService { ListResponse getNetworks(ListTungstenNetworkCmd cmd) throws IOException; ListResponse getVmInterfaces(ListTungstenVmInterfaceCmd cmd) - throws IOException; + throws IOException; ListResponse getVirtualMachines(ListTungstenVirtualMachineCmd cmd) - throws IOException; + throws IOException; VirtualNetwork createTungstenNetwork(CreateTungstenNetworkCmd cmd); @@ -44,9 +46,11 @@ ListResponse getVirtualMachines(ListTungstenVirt VirtualNetwork deleteTungstenNetwork(DeleteTungstenNetworkCmd cmd) throws IOException; ApiObjectBase getTungstenObjectByUUID(Class cls, String uuid) - throws IOException; + throws IOException; SuccessResponse addVRouterPort(AddVRouterPortCmd cmd) throws IOException; SuccessResponse deleteVRouterPort(DeleteVRouterPortCmd cmd) throws IOException; + + ListResponse getVirtualRouters(ListTungstenVirtualRouterCmd cmd) throws IOException; } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java index 98bfb4722904..b89c5c47cc30 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java @@ -1,22 +1,13 @@ package org.apache.cloudstack.network.tungsten.service; -import com.cloud.exception.InvalidParameterValueException; -import com.cloud.utils.PropertiesUtil; import com.cloud.utils.component.ManagerBase; import com.google.common.collect.Lists; -import net.juniper.contrail.api.ApiConnector; -import net.juniper.contrail.api.ApiConnectorFactory; import net.juniper.contrail.api.ApiObjectBase; import net.juniper.contrail.api.types.InstanceIp; -import net.juniper.contrail.api.types.MacAddressesType; -import net.juniper.contrail.api.types.NetworkIpam; -import net.juniper.contrail.api.types.Project; -import net.juniper.contrail.api.types.SecurityGroup; -import net.juniper.contrail.api.types.SubnetType; import net.juniper.contrail.api.types.VirtualMachine; import net.juniper.contrail.api.types.VirtualMachineInterface; import net.juniper.contrail.api.types.VirtualNetwork; -import net.juniper.contrail.api.types.VnSubnetsType; +import net.juniper.contrail.api.types.VirtualRouter; import org.apache.cloudstack.api.response.ListResponse; import org.apache.cloudstack.api.response.SuccessResponse; import org.apache.cloudstack.framework.config.ConfigKey; @@ -30,105 +21,55 @@ import org.apache.cloudstack.network.tungsten.api.command.DeleteVRouterPortCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenNetworkCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVirtualMachineCmd; +import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVirtualRouterCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVmInterfaceCmd; import org.apache.cloudstack.network.tungsten.api.response.TungstenNetworkResponse; import org.apache.cloudstack.network.tungsten.api.response.TungstenVirtualMachineResponse; +import org.apache.cloudstack.network.tungsten.api.response.TungstenVirtualRouterResponse; import org.apache.cloudstack.network.tungsten.api.response.TungstenVmInterfaceResponse; import org.apache.cloudstack.network.tungsten.vrouter.Port; -import org.apache.cloudstack.network.tungsten.vrouter.VRouterApiConnector; -import org.apache.cloudstack.network.tungsten.vrouter.VRouterApiConnectorFactory; -import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; +import javax.inject.Inject; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Properties; - -import javax.annotation.PostConstruct; -import javax.naming.ConfigurationException; @Component public class TungstenManagerImpl extends ManagerBase implements TungstenManager, Configurable { private static final Logger s_logger = Logger.getLogger(TungstenManager.class); - private ApiConnector _api; - private VRouterApiConnector _vrouterApi; - private final String configuration = "plugins/network-elements/tungsten/conf/tungsten.properties"; - - @PostConstruct - public void init() throws ConfigurationException { - File configFile = PropertiesUtil.findConfigFile(configuration); - FileInputStream fileStream = null; - try { - String hostname = null; - int port = 0; - String vrouterHost = null; - String vrouterPort = null; - if (configFile == null) { - throw new FileNotFoundException("Tungsten config file not found!"); - } else { - final Properties configProps = new Properties(); - fileStream = new FileInputStream(configFile); - configProps.load(fileStream); - - hostname = configProps.getProperty("tungsten.api.hostname"); - String portStr = configProps.getProperty("tungsten.api.port"); - - if (portStr != null && portStr.length() > 0) { - port = Integer.parseInt(portStr); - } - - vrouterHost = configProps.getProperty("tungsten.vrouter.hostname"); - vrouterPort = configProps.getProperty("tungsten.vrouter.port"); - } - _api = ApiConnectorFactory.build(hostname, port); - _vrouterApi = VRouterApiConnectorFactory.getInstance(vrouterHost, vrouterPort); - } catch (IOException ex) { - s_logger.warn("Unable to read " + configuration, ex); - throw new ConfigurationException(); - } catch (Exception ex) { - s_logger.debug("Exception in configure: " + ex); - ex.printStackTrace(); - throw new ConfigurationException(); - } finally { - IOUtils.closeQuietly(fileStream); - } - } + @Inject + TungstenService tungstenService; @Override public List> getCommands() { return Lists.>newArrayList(ListTungstenNetworkCmd.class, - CreateTungstenNetworkCmd.class, DeleteTungstenNetworkCmd.class, - CreateTungstenVmInterfaceCmd.class, CreateTungstenVirtualMachineCmd.class, - CreateTungstenInstanceIpCmd.class, ListTungstenVirtualMachineCmd.class, - ListTungstenVmInterfaceCmd.class, AddVRouterPortCmd.class, DeleteVRouterPortCmd.class); + CreateTungstenNetworkCmd.class, DeleteTungstenNetworkCmd.class, + CreateTungstenVmInterfaceCmd.class, CreateTungstenVirtualMachineCmd.class, + CreateTungstenInstanceIpCmd.class, ListTungstenVirtualMachineCmd.class, + ListTungstenVmInterfaceCmd.class, AddVRouterPortCmd.class, DeleteVRouterPortCmd.class, + ListTungstenVirtualRouterCmd.class + ); } @Override - public ListResponse getNetworks(ListTungstenNetworkCmd cmd) - throws IOException { + public ListResponse getNetworks(ListTungstenNetworkCmd cmd) throws IOException{ List networks; ListResponse response = new ListResponse<>(); List tungstenNetworkResponses = new ArrayList<>(); - if (cmd.getNetworkUUID() != null) - networks = Arrays.asList( - (VirtualNetwork) _api.findById(VirtualNetwork.class, cmd.getNetworkUUID())); + if(cmd.getNetworkUUID() != null) + networks = Arrays.asList(tungstenService.getVirtualNetworkFromTungsten(cmd.getNetworkUUID())); else - networks = (List) _api.list(VirtualNetwork.class, null); + networks = (List) tungstenService.get_api().list(VirtualNetwork.class, null); - if (networks != null && !networks.isEmpty()) { - for (VirtualNetwork virtualNetwork : networks) { - TungstenNetworkResponse tungstenNetworkResponse = - TungstenResponseHelper.createTungstenNetworkResponse( - virtualNetwork); + if(networks != null && !networks.isEmpty()){ + for(VirtualNetwork virtualNetwork : networks){ + TungstenNetworkResponse tungstenNetworkResponse = TungstenResponseHelper.createTungstenNetworkResponse(virtualNetwork); tungstenNetworkResponses.add(tungstenNetworkResponse); } } @@ -137,24 +78,40 @@ public ListResponse getNetworks(ListTungstenNetworkCmd } @Override - public ListResponse getVmInterfaces(ListTungstenVmInterfaceCmd cmd) - throws IOException { + public ListResponse getVirtualRouters(ListTungstenVirtualRouterCmd cmd) throws IOException { + List virtualRouters; + ListResponse response = new ListResponse<>(); + List tungstenVirtualRouterResponses = new ArrayList<>(); + + if(cmd.getVirtualRouterUuid() != null) + virtualRouters = Arrays.asList((VirtualRouter)getTungstenObjectByUUID(VirtualRouter.class, cmd.getVirtualRouterUuid())); + else + virtualRouters = (List) tungstenService.get_api().list(VirtualRouter.class, null); + + if(virtualRouters != null & !virtualRouters.isEmpty()){ + for(VirtualRouter virtualRouter : virtualRouters){ + TungstenVirtualRouterResponse tungstenVirtualRouterResponse = TungstenResponseHelper.createTungstenVirtualRouterResponse(virtualRouter); + tungstenVirtualRouterResponses.add(tungstenVirtualRouterResponse); + } + } + response.setResponses(tungstenVirtualRouterResponses); + return response; + } + + @Override + public ListResponse getVmInterfaces(ListTungstenVmInterfaceCmd cmd) throws IOException{ List vmInterfaces; ListResponse response = new ListResponse<>(); List tungstenVmInterfaceResponses = new ArrayList<>(); - if (cmd.getVmInterfaceUUID() != null) - vmInterfaces = Arrays.asList( - (VirtualMachineInterface) getTungstenObjectByUUID(VirtualMachineInterface.class, - cmd.getVmInterfaceUUID())); + if(cmd.getVmInterfaceUUID() != null) + vmInterfaces = Arrays.asList((VirtualMachineInterface)getTungstenObjectByUUID(VirtualMachineInterface.class, cmd.getVmInterfaceUUID())); else - vmInterfaces = (List) _api.list(VirtualMachineInterface.class, null); + vmInterfaces = (List) tungstenService.get_api().list(VirtualMachineInterface.class, null); - if (vmInterfaces != null && !vmInterfaces.isEmpty()) { - for (VirtualMachineInterface vmInterface : vmInterfaces) { - TungstenVmInterfaceResponse tungstenVmInterfaceResponse = - TungstenResponseHelper.createTungstenVmInterfaceResponse( - vmInterface); + if(vmInterfaces != null && !vmInterfaces.isEmpty()){ + for(VirtualMachineInterface vmInterface : vmInterfaces){ + TungstenVmInterfaceResponse tungstenVmInterfaceResponse = TungstenResponseHelper.createTungstenVmInterfaceResponse(vmInterface); tungstenVmInterfaceResponses.add(tungstenVmInterfaceResponse); } } @@ -162,23 +119,19 @@ public ListResponse getVmInterfaces(ListTungstenVmI return response; } - public ListResponse getVirtualMachines( - ListTungstenVirtualMachineCmd cmd) throws IOException { + public ListResponse getVirtualMachines(ListTungstenVirtualMachineCmd cmd) throws IOException{ List virtualMachines; ListResponse response = new ListResponse<>(); List tungstenVirtualMachineResponses = new ArrayList<>(); - if (cmd.getVirtualMachineUUID() != null) - virtualMachines = Arrays.asList( - (VirtualMachine) _api.findById(VirtualMachine.class, cmd.getVirtualMachineUUID())); + if(cmd.getVirtualMachineUUID() != null) + virtualMachines = Arrays.asList((VirtualMachine)tungstenService.get_api().findById(VirtualMachine.class, cmd.getVirtualMachineUUID())); else - virtualMachines = (List) _api.list(VirtualMachine.class, null); + virtualMachines = (List) tungstenService.get_api().list(VirtualMachine.class, null); - if (virtualMachines != null && !virtualMachines.isEmpty()) { - for (VirtualMachine virtualMachine : virtualMachines) { - TungstenVirtualMachineResponse tungstenVirtualMachineResponse = - TungstenResponseHelper.createTungstenVirtualMachineResponse( - virtualMachine); + if(virtualMachines != null && !virtualMachines.isEmpty()){ + for(VirtualMachine virtualMachine : virtualMachines){ + TungstenVirtualMachineResponse tungstenVirtualMachineResponse = TungstenResponseHelper.createTungstenVirtualMachineResponse(virtualMachine); tungstenVirtualMachineResponses.add(tungstenVirtualMachineResponse); } } @@ -187,133 +140,41 @@ public ListResponse getVirtualMachines( } @Override - public VirtualNetwork createTungstenNetwork(CreateTungstenNetworkCmd cmd) { - VirtualNetwork network = new VirtualNetwork(); - try { - network.setName(cmd.getName()); - network.setNetworkIpam(getNetworkIpam(cmd), getVnSubnetsType(cmd)); - _api.create(network); - return (VirtualNetwork) _api.findByFQN(VirtualNetwork.class, getFqnName(network)); - } catch (IOException e) { - s_logger.error("Unable to read " + configuration, e); - return null; - } + public VirtualNetwork createTungstenNetwork(CreateTungstenNetworkCmd cmd){ + return tungstenService.createNetworkInTungsten(cmd.getTungstenNetworkUuid(), cmd.getName(), cmd.getNetworkIpamUUID(), cmd.getIpAllocPoolStart(), + cmd.getIpAllocPoolEnd(), cmd.getSubnetIpPrefix(), cmd.getSubnetIpPrefixLength(), cmd.getDefaultGateway(), cmd.isEnableDHCP(), + cmd.getDnsNameservers(), cmd.isAddrFromStart()); } @Override - public VirtualMachine createTungstenVirtualMachine(CreateTungstenVirtualMachineCmd cmd) { - VirtualMachine virtualMachine = new VirtualMachine(); - try { - virtualMachine.setName(cmd.getName()); - _api.create(virtualMachine); - return (VirtualMachine) _api.findByFQN(VirtualMachine.class, getFqnName(virtualMachine)); - } catch (IOException e) { - s_logger.error("Unable to read " + configuration, e); - return null; - } + public VirtualMachine createTungstenVirtualMachine(CreateTungstenVirtualMachineCmd cmd){ + return tungstenService.createVmInTungsten(cmd.getTungstenVmUuid(), cmd.getName()); } @Override - public InstanceIp createInstanceIp(CreateTungstenInstanceIpCmd cmd) { - InstanceIp instanceIp = new InstanceIp(); - try { - instanceIp.setName(cmd.getName()); - VirtualMachineInterface virtualMachineInterface = - (VirtualMachineInterface) getTungstenObjectByUUID( - VirtualMachineInterface.class, cmd.getTungstenVmInterfaceUuid()); - VirtualNetwork virtualNetwork = (VirtualNetwork) getTungstenObjectByUUID(VirtualNetwork.class, - cmd.getTungstenNetworkUuid()); - if (virtualNetwork != null) - instanceIp.setVirtualNetwork(virtualNetwork); - if (virtualMachineInterface != null) - instanceIp.setVirtualMachineInterface(virtualMachineInterface); - instanceIp.setAddress(cmd.getTungstenInstanceIpAddress()); - _api.create(instanceIp); - return (InstanceIp) _api.findByFQN(InstanceIp.class, getFqnName(instanceIp)); - } catch (IOException e) { - s_logger.error("Unable to read " + configuration, e); - return null; - } + public InstanceIp createInstanceIp(CreateTungstenInstanceIpCmd cmd){ + return tungstenService.createInstanceIpInTungsten(cmd.getName(), cmd.getTungstenVmInterfaceUuid(), + cmd.getTungstenNetworkUuid(), cmd.getTungstenInstanceIpAddress()); } @Override - public VirtualMachineInterface createTungstenVirtualMachineInterface( - CreateTungstenVmInterfaceCmd cmd) { - VirtualMachineInterface virtualMachineInterface = new VirtualMachineInterface(); - try { - virtualMachineInterface.setName(cmd.getName()); - Project project = (Project) getTungstenObjectByUUID(Project.class, - cmd.getTungstenProjectUuid()); - VirtualNetwork virtualNetwork = (VirtualNetwork) getTungstenObjectByUUID(VirtualNetwork.class, - cmd.getTungstenNetworkUuid()); - VirtualMachine virtualMachine = (VirtualMachine) getTungstenObjectByUUID(VirtualMachine.class, - cmd.getTungstenVirtualMachineUuid()); - SecurityGroup securityGroup = (SecurityGroup) getTungstenObjectByUUID(SecurityGroup.class, - cmd.getTungstenSecurityGroupUuid()); - if (virtualNetwork != null) - virtualMachineInterface.setVirtualNetwork(virtualNetwork); - if (virtualMachine != null) - virtualMachineInterface.setVirtualMachine(virtualMachine); - if (securityGroup != null) - virtualMachineInterface.setSecurityGroup(securityGroup); - if (project != null) - virtualMachineInterface.setParent(project); - if (cmd.getTungstenVmInterfaceMacAddresses() != null - && !cmd.getTungstenVmInterfaceMacAddresses().isEmpty()) - virtualMachineInterface.setMacAddresses( - new MacAddressesType(cmd.getTungstenVmInterfaceMacAddresses())); - _api.create(virtualMachineInterface); - return (VirtualMachineInterface) _api.findByFQN(VirtualMachineInterface.class, - getFqnName(virtualMachineInterface)); - } catch (IOException e) { - s_logger.error("Unable to read " + configuration, e); - return null; - } + public VirtualMachineInterface createTungstenVirtualMachineInterface(CreateTungstenVmInterfaceCmd cmd){ + return tungstenService.createVmInterfaceInTungsten(cmd.getName(), cmd.getTungstenProjectUuid(), cmd.getTungstenNetworkUuid(), + cmd.getTungstenVirtualMachineUuid(), cmd.getTungstenSecurityGroupUuid(), + cmd.getTungstenVmInterfaceMacAddresses()); } @Override - public ApiObjectBase getTungstenObjectByUUID(Class cls, String uuid) - throws IOException { - if (uuid != null) - return _api.findById(cls, uuid); + public ApiObjectBase getTungstenObjectByUUID(Class cls, String uuid) throws IOException { + if(uuid != null) + return tungstenService.get_api().findById(cls, uuid); else return null; } - public NetworkIpam getNetworkIpam(CreateTungstenNetworkCmd cmd) throws IOException { - if (cmd.getNetworkIpamUUID() != null) { - NetworkIpam networkIpam = (NetworkIpam) _api.findById(NetworkIpam.class, - cmd.getNetworkIpamUUID()); - if (networkIpam != null) - return networkIpam; - } - NetworkIpam networkIpam = new NetworkIpam(); - networkIpam.setName(cmd.getName() + "-ipam"); - _api.create(networkIpam); - return (NetworkIpam) _api.findByFQN(NetworkIpam.class, getFqnName(networkIpam)); - } - - public VnSubnetsType getVnSubnetsType(CreateTungstenNetworkCmd cmd) { - List allocationPoolTypes = new ArrayList<>(); - allocationPoolTypes.add( - new VnSubnetsType.IpamSubnetType.AllocationPoolType(cmd.getIpAllocPoolStart(), - cmd.getIpAllocPoolEnd())); - VnSubnetsType.IpamSubnetType ipamSubnetType = new VnSubnetsType.IpamSubnetType( - new SubnetType(cmd.getSubnetIpPrefix(), cmd.getSubnetIpPrefixLength()), - cmd.getDefaultGateway(), null, cmd.isEnableDHCP(), cmd.getDnsNameservers(), - allocationPoolTypes, cmd.isAddrFromStart(), null, null, null); - return new VnSubnetsType(Arrays.asList(ipamSubnetType), null); - } - @Override public VirtualNetwork deleteTungstenNetwork(DeleteTungstenNetworkCmd cmd) throws IOException { - VirtualNetwork network = (VirtualNetwork) _api.findById(VirtualNetwork.class, cmd.getUuid()); - if (network != null) { - _api.delete(network); - return network; - } else - throw new InvalidParameterValueException( - "Unable to find tungsten network with UUID: " + cmd.getUuid()); + return tungstenService.deleteNetworkFromTungsten(cmd.getTungstenNetworkUuid()); } @Override @@ -328,7 +189,7 @@ public SuccessResponse addVRouterPort(final AddVRouterPortCmd cmd) throws IOExce port.setDisplayName(cmd.getTungstenVmName()); port.setVnId(cmd.getTungstenVnUuid()); SuccessResponse successResponse = new SuccessResponse(cmd.getCommandName()); - if (_vrouterApi.addPort(port)) { + if (tungstenService.get_vrouterApi().addPort(port)) { successResponse.setSuccess(true); successResponse.setDisplayText("Success to add vrouter port"); } else { @@ -342,7 +203,7 @@ public SuccessResponse addVRouterPort(final AddVRouterPortCmd cmd) throws IOExce public SuccessResponse deleteVRouterPort(final DeleteVRouterPortCmd cmd) throws IOException { String portId = cmd.getTungstenVmInterfaceUuid(); SuccessResponse successResponse = new SuccessResponse(cmd.getCommandName()); - if (_vrouterApi.deletePort(portId)) { + if (tungstenService.get_vrouterApi().deletePort(portId)) { successResponse.setSuccess(true); successResponse.setDisplayText("Success to delete vrouter port"); } else { @@ -362,16 +223,6 @@ public ConfigKey[] getConfigKeys() { return new ConfigKey[0]; } - public String getFqnName(ApiObjectBase obj) { - StringBuilder sb = new StringBuilder(); - for (String item : obj.getQualifiedName()) { - sb.append(item); - sb.append(":"); - } - sb.deleteCharAt(sb.toString().length() - 1); - return sb.toString(); - } - private String getTapName(final String macAddress) { return "tap" + macAddress.replace(":", ""); } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java index 8f2ce3f24f0d..9a9b67993080 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java @@ -6,9 +6,11 @@ import net.juniper.contrail.api.types.VirtualMachine; import net.juniper.contrail.api.types.VirtualMachineInterface; import net.juniper.contrail.api.types.VirtualNetwork; +import net.juniper.contrail.api.types.VirtualRouter; import org.apache.cloudstack.network.tungsten.api.response.TungstenInstanceIpResponse; import org.apache.cloudstack.network.tungsten.api.response.TungstenNetworkResponse; import org.apache.cloudstack.network.tungsten.api.response.TungstenVirtualMachineResponse; +import org.apache.cloudstack.network.tungsten.api.response.TungstenVirtualRouterResponse; import org.apache.cloudstack.network.tungsten.api.response.TungstenVmInterfaceResponse; public class TungstenResponseHelper { @@ -59,6 +61,14 @@ public static TungstenVmInterfaceResponse createTungstenVmInterfaceResponse(Virt return tungstenVmInterfaceResponse; } + public static TungstenVirtualRouterResponse createTungstenVirtualRouterResponse(VirtualRouter virtualRouter){ + TungstenVirtualRouterResponse tungstenVirtualRouterResponse = new TungstenVirtualRouterResponse(); + tungstenVirtualRouterResponse.setUuid(virtualRouter.getUuid()); + tungstenVirtualRouterResponse.setName(virtualRouter.getName()); + tungstenVirtualRouterResponse.setObjectName("tungstenVirtualRouter"); + return tungstenVirtualRouterResponse; + } + public static TungstenInstanceIpResponse createTungstenInstanceIpResponse(InstanceIp instanceIp){ TungstenInstanceIpResponse tungstenInstanceIpResponse = new TungstenInstanceIpResponse(); tungstenInstanceIpResponse.setName(instanceIp.getName()); diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenService.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenService.java new file mode 100644 index 000000000000..4572653f5126 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenService.java @@ -0,0 +1,36 @@ +package org.apache.cloudstack.network.tungsten.service; + +import net.juniper.contrail.api.ApiConnector; +import net.juniper.contrail.api.types.InstanceIp; +import net.juniper.contrail.api.types.VirtualMachine; +import net.juniper.contrail.api.types.VirtualMachineInterface; +import net.juniper.contrail.api.types.VirtualNetwork; +import org.apache.cloudstack.network.tungsten.vrouter.VRouterApiConnector; + +import java.io.IOException; +import java.util.List; + +public interface TungstenService { + + ApiConnector get_api(); + + VRouterApiConnector get_vrouterApi(); + + VirtualNetwork createNetworkInTungsten(String networkUuid, String networkName, String networkIpamUuid, String ipAllocPoolStart, + String ipAllocPoolEnd, String subnetIpPrefix, int subnetIpPrefixLength, String defaultGateway, + boolean isDhcpEnabled, List dnsNameservers, boolean isIpAddrFromStart); + + VirtualMachine createVmInTungsten(String vmUuid, String vmName); + + InstanceIp createInstanceIpInTungsten(String instanceIpName, String tungstenVmInterfaceUuid, String tungstenNetworkUuid, + String tungstenInstanceIpAddress); + + VirtualMachineInterface createVmInterfaceInTungsten(String vmInterfaceName, String tungstenProjectUuid, String tungstenNetworkUuid, + String tungstenVmUuid, String tungstenSecurityGroupUuid, List tungstenVmInterfaceMacAddresses); + + VirtualNetwork deleteNetworkFromTungsten(String tungstenNetworkUuid) throws IOException; + + VirtualNetwork getVirtualNetworkFromTungsten(String virtualNetworkUuid) throws IOException; + + void expugeVmFromTungsten(String vmUuid) throws IOException; +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImpl.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImpl.java new file mode 100644 index 000000000000..cfd2f23cf4c4 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImpl.java @@ -0,0 +1,237 @@ +package org.apache.cloudstack.network.tungsten.service; + +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.utils.PropertiesUtil; +import net.juniper.contrail.api.ApiConnector; +import net.juniper.contrail.api.ApiConnectorFactory; +import net.juniper.contrail.api.ApiObjectBase; +import net.juniper.contrail.api.types.InstanceIp; +import net.juniper.contrail.api.types.MacAddressesType; +import net.juniper.contrail.api.types.NetworkIpam; +import net.juniper.contrail.api.types.Project; +import net.juniper.contrail.api.types.SecurityGroup; +import net.juniper.contrail.api.types.SubnetType; +import net.juniper.contrail.api.types.VirtualMachine; +import net.juniper.contrail.api.types.VirtualMachineInterface; +import net.juniper.contrail.api.types.VirtualNetwork; +import net.juniper.contrail.api.types.VnSubnetsType; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.network.tungsten.vrouter.VRouterApiConnector; +import org.apache.cloudstack.network.tungsten.vrouter.VRouterApiConnectorFactory; +import org.apache.commons.io.IOUtils; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.annotation.PostConstruct; +import javax.naming.ConfigurationException; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; + +@Component +public class TungstenServiceImpl implements TungstenService { + + private static final Logger s_logger = Logger.getLogger(TungstenServiceImpl.class); + + private ApiConnector _api; + private final String configuration = "plugins/network-elements/tungsten/conf/tungsten.properties"; + private VRouterApiConnector _vrouterApi; + + public ApiConnector get_api() { + return _api; + } + + public VRouterApiConnector get_vrouterApi() { + return _vrouterApi; + } + + @PostConstruct + public void init() throws ConfigurationException { + File configFile = PropertiesUtil.findConfigFile(configuration); + FileInputStream fileStream = null; + try { + String hostname = null; + int port = 0; + String vrouterHost = null; + String vrouterPort = null; + if (configFile == null) { + throw new FileNotFoundException("Tungsten config file not found!"); + } else { + final Properties configProps = new Properties(); + fileStream = new FileInputStream(configFile); + configProps.load(fileStream); + + hostname = configProps.getProperty("tungsten.api.hostname"); + String portStr = configProps.getProperty("tungsten.api.port"); + if (portStr != null && portStr.length() > 0) { + port = Integer.parseInt(portStr); + } + + vrouterHost = configProps.getProperty("tungsten.vrouter.hostname"); + vrouterPort = configProps.getProperty("tungsten.vrouter.port"); + } + _api = ApiConnectorFactory.build(hostname, port); + _vrouterApi = VRouterApiConnectorFactory.getInstance(vrouterHost, vrouterPort); + } catch (IOException ex) { + s_logger.warn("Unable to read " + configuration, ex); + throw new ConfigurationException(); + } catch (Exception ex) { + s_logger.debug("Exception in configure: " + ex); + ex.printStackTrace(); + throw new ConfigurationException(); + } finally { + IOUtils.closeQuietly(fileStream); + } + } + + @Override + public VirtualNetwork createNetworkInTungsten(String networkUuid, String networkName, String networkIpamUuid, String ipAllocPoolStart, + String ipAllocPoolEnd, String subnetIpPrefix, int subnetIpPrefixLength, String defaultGateway, + boolean isDhcpEnabled, List dnsNameservers, boolean isIpAddrFromStart){ + VirtualNetwork network = new VirtualNetwork(); + try { + network.setName(networkName); + network.setNetworkIpam(getNetworkIpam(networkName, networkIpamUuid), getVnSubnetsType(ipAllocPoolStart, ipAllocPoolEnd, subnetIpPrefix, + subnetIpPrefixLength, defaultGateway, isDhcpEnabled, dnsNameservers, isIpAddrFromStart)); + _api.create(network); + return (VirtualNetwork) _api.findByFQN(VirtualNetwork.class, getFqnName(network)); + } catch (IOException e) { + s_logger.error("Unable to read " + configuration, e); + return null; + } + } + + @Override + public VirtualNetwork deleteNetworkFromTungsten(String tungstenNetworkUuid) throws IOException { + VirtualNetwork network = (VirtualNetwork)_api.findById(VirtualNetwork.class, tungstenNetworkUuid); + if(network != null) { + if(network.getVirtualMachineInterfaceBackRefs() != null) + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete network"); + _api.delete(network); + return network; + } + else + throw new InvalidParameterValueException("Unable to find tungsten network with UUID: " + tungstenNetworkUuid); + } + + @Override + public VirtualMachine createVmInTungsten(String vmUuid, String vmName){ + VirtualMachine virtualMachine = new VirtualMachine(); + try { + virtualMachine.setName(vmName); + virtualMachine.setUuid(vmUuid); + _api.create(virtualMachine); + return (VirtualMachine) _api.findByFQN(VirtualMachine.class, getFqnName(virtualMachine)); + } catch (IOException e) { + s_logger.error("Unable to read " + configuration, e); + return null; + } + } + + @Override + public InstanceIp createInstanceIpInTungsten(String instanceIpName, String tungstenVmInterfaceUuid, String tungstenNetworkUuid, + String tungstenInstanceIpAddress){ + InstanceIp instanceIp = new InstanceIp(); + try{ + instanceIp.setName(instanceIpName); + VirtualMachineInterface virtualMachineInterface = (VirtualMachineInterface) _api.findById(VirtualMachineInterface.class, tungstenVmInterfaceUuid); + VirtualNetwork virtualNetwork = (VirtualNetwork) _api.findById(VirtualNetwork.class, tungstenNetworkUuid); + if(virtualNetwork != null) + instanceIp.setVirtualNetwork(virtualNetwork); + if(virtualMachineInterface != null) + instanceIp.setVirtualMachineInterface(virtualMachineInterface); + instanceIp.setAddress(tungstenInstanceIpAddress); + _api.create(instanceIp); + return (InstanceIp) _api.findByFQN(InstanceIp.class, getFqnName(instanceIp)); + } catch (IOException e) { + s_logger.error("Unable to read " + configuration, e); + return null; + } + } + + @Override + public VirtualMachineInterface createVmInterfaceInTungsten(String vmInterfaceName, String tungstenProjectUuid, String tungstenNetworkUuid, + String tungstenVmUuid, String tungstenSecurityGroupUuid, List tungstenVmInterfaceMacAddresses){ + VirtualMachineInterface virtualMachineInterface = new VirtualMachineInterface(); + try { + virtualMachineInterface.setName(vmInterfaceName); + Project project = (Project) _api.findById(Project.class, tungstenProjectUuid); + VirtualNetwork virtualNetwork = (VirtualNetwork) _api.findById(VirtualNetwork.class, tungstenNetworkUuid); + VirtualMachine virtualMachine = (VirtualMachine) _api.findById(VirtualMachine.class, tungstenVmUuid); + SecurityGroup securityGroup = (SecurityGroup) _api.findById(SecurityGroup.class, tungstenSecurityGroupUuid); + if(virtualNetwork != null) + virtualMachineInterface.setVirtualNetwork(virtualNetwork); + if(virtualMachine != null) + virtualMachineInterface.setVirtualMachine(virtualMachine); + if(securityGroup != null) + virtualMachineInterface.setSecurityGroup(securityGroup); + if(project != null) + virtualMachineInterface.setParent(project); + if(tungstenVmInterfaceMacAddresses != null && !tungstenVmInterfaceMacAddresses.isEmpty()) + virtualMachineInterface.setMacAddresses(new MacAddressesType(tungstenVmInterfaceMacAddresses)); + _api.create(virtualMachineInterface); + return (VirtualMachineInterface) _api.findByFQN(VirtualMachineInterface.class, getFqnName(virtualMachineInterface)); + } catch (IOException e) { +// s_logger.error("Unable to read " + configuration, e); + return null; + } + } + + @Override + public VirtualNetwork getVirtualNetworkFromTungsten(String virtualNetworkUuid) throws IOException { + return (VirtualNetwork)_api.findById(VirtualNetwork.class, virtualNetworkUuid); + } + + @Override + public void expugeVmFromTungsten(String vmUuid) throws IOException { + VirtualMachine virtualMachine = (VirtualMachine) _api.findById(VirtualMachine.class, vmUuid); + if(virtualMachine == null) + return; + if(virtualMachine.getVirtualMachineInterfaceBackRefs() != null && virtualMachine.getVirtualMachineInterfaceBackRefs().size() > 0) { + VirtualMachineInterface virtualMachineInterface = (VirtualMachineInterface) _api.findById(VirtualMachineInterface.class, virtualMachine.getVirtualMachineInterfaceBackRefs().get(0).getUuid()); + _api.delete(VirtualMachineInterface.class, virtualMachineInterface.getUuid()); + } + _api.delete(VirtualMachine.class, virtualMachine.getUuid()); + } + + public VnSubnetsType getVnSubnetsType(String ipAllocPoolStart, + String ipAllocPoolEnd, String subnetIpPrefix, int subnetIpPrefixLength, String defaultGateway, + boolean isDhcpEnabled, List dnsNameservers, boolean isIpAddrFromStart){ + List allocationPoolTypes = new ArrayList<>(); + if(ipAllocPoolStart != null && ipAllocPoolEnd != null) { + allocationPoolTypes.add(new VnSubnetsType.IpamSubnetType.AllocationPoolType(ipAllocPoolStart, ipAllocPoolEnd)); + } + VnSubnetsType.IpamSubnetType ipamSubnetType = new VnSubnetsType.IpamSubnetType( + new SubnetType(subnetIpPrefix, subnetIpPrefixLength), defaultGateway, + null, isDhcpEnabled, dnsNameservers, allocationPoolTypes, isIpAddrFromStart, null, null, null); + return new VnSubnetsType(Arrays.asList(ipamSubnetType), null); + } + + public NetworkIpam getNetworkIpam(String networkName, String networkIpamUuid) throws IOException { + if(networkIpamUuid != null){ + NetworkIpam networkIpam = (NetworkIpam) _api.findById(NetworkIpam.class, networkIpamUuid); + if(networkIpam != null) + return networkIpam; + } + NetworkIpam networkIpam = new NetworkIpam(); + networkIpam.setName(networkName + "-ipam"); + _api.create(networkIpam); + return (NetworkIpam) _api.findByFQN(NetworkIpam.class, getFqnName(networkIpam)); + } + + public String getFqnName(ApiObjectBase obj){ + StringBuilder sb = new StringBuilder(); + for(String item : obj.getQualifiedName()){ + sb.append(item); + sb.append(":"); + } + sb.deleteCharAt(sb.toString().length()-1); + return sb.toString(); + } +} diff --git a/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/spring-tungsten-context.xml b/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/spring-tungsten-context.xml index 2ae530b44b39..6e5544e0d377 100644 --- a/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/spring-tungsten-context.xml +++ b/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/spring-tungsten-context.xml @@ -26,7 +26,18 @@ http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd"> + class="org.apache.cloudstack.network.tungsten.service.TungstenManagerImpl"/> + + + + + + + + + + diff --git a/server/src/main/java/com/cloud/api/ApiResponseHelper.java b/server/src/main/java/com/cloud/api/ApiResponseHelper.java index af746ef6f748..5f0d07856fe9 100644 --- a/server/src/main/java/com/cloud/api/ApiResponseHelper.java +++ b/server/src/main/java/com/cloud/api/ApiResponseHelper.java @@ -622,8 +622,8 @@ public SnapshotResponse createSnapshotResponse(Snapshot snapshot) { s_logger.debug("Unable to find info for image store snapshot with uuid " + snapshot.getUuid()); snapshotResponse.setRevertable(false); } else { - snapshotResponse.setRevertable(snapshotInfo.isRevertable()); - snapshotResponse.setPhysicaSize(snapshotInfo.getPhysicalSize()); + snapshotResponse.setRevertable(snapshotInfo.isRevertable()); + snapshotResponse.setPhysicaSize(snapshotInfo.getPhysicalSize()); } // set tag information @@ -1603,10 +1603,10 @@ public SystemVmResponse createSystemVmResponse(VirtualMachine vm) { vmResponse.setGateway(singleNicProfile.getIPv4Gateway()); } else if (network.getTrafficType() == TrafficType.Guest) { /* - * In basic zone, public ip has TrafficType.Guest in case EIP service is not enabled. - * When EIP service is enabled in the basic zone, system VM by default get the public - * IP allocated for EIP. So return the guest/public IP accordingly. - * */ + * In basic zone, public ip has TrafficType.Guest in case EIP service is not enabled. + * When EIP service is enabled in the basic zone, system VM by default get the public + * IP allocated for EIP. So return the guest/public IP accordingly. + * */ NetworkOffering networkOffering = ApiDBUtils.findNetworkOfferingById(network.getNetworkOfferingId()); if (networkOffering.isElasticIp()) { IpAddress ip = ApiDBUtils.findIpByAssociatedVmId(vm.getId()); @@ -2210,6 +2210,7 @@ public NetworkOfferingResponse createNetworkOfferingResponse(NetworkOffering off serviceResponses.add(svcRsp); } response.setForVpc(_configMgr.isOfferingForVpc(offering)); + response.setForTungsten(offering.isForTungsten()); response.setServices(serviceResponses); //set network offering details Map details = _ntwkModel.getNtwkOffDetails(offering.getId()); @@ -2319,10 +2320,10 @@ public NetworkResponse createNetworkResponse(ResponseView view, Network network) response.setBroadcastUri(broadcastUri); String vlan = "N/A"; switch (BroadcastDomainType.getSchemeValue(network.getBroadcastUri())) { - case Vlan: - case Vxlan: - vlan = BroadcastDomainType.getValue(network.getBroadcastUri()); - break; + case Vlan: + case Vxlan: + vlan = BroadcastDomainType.getValue(network.getBroadcastUri()); + break; } // return vlan information only to Root admin response.setVlan(vlan); @@ -2612,8 +2613,8 @@ public FirewallResponse createFirewallResponse(FirewallRule fwRule) { response.setPublicIpAddress(ip.getAddress().addr()); } - Network network = ApiDBUtils.findNetworkById(fwRule.getNetworkId()); - response.setNetworkId(network.getUuid()); + Network network = ApiDBUtils.findNetworkById(fwRule.getNetworkId()); + response.setNetworkId(network.getUuid()); FirewallRule.State state = fwRule.getState(); String stateToSet = state.toString(); @@ -4033,7 +4034,7 @@ public UsageRecordResponse createUsageResponse(Usage usageRecord, Map configValuesForValidation; private Set weightBasedParametersForValidation; private Set overprovisioningFactorsForValidation; - public static final String VM_USERDATA_MAX_LENGTH_STRING = "vm.userdata.max.length"; public static final ConfigKey SystemVMUseLocalStorage = new ConfigKey(Boolean.class, "system.vm.use.local.storage", "Advanced", "false", "Indicates whether to use local storage pools or shared storage pools for system VMs.", false, ConfigKey.Scope.Zone, null); @@ -461,28 +409,6 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati "Maximum IOPS read burst duration (seconds). If '0' (zero) then does not check for maximum burst length.", true, ConfigKey.Scope.Global, null); public final static ConfigKey IOPS_MAX_WRITE_LENGTH = new ConfigKey(Long.class, "vm.disk.iops.maximum.write.length", "Advanced", "0", "Maximum IOPS write burst duration (seconds). If '0' (zero) then does not check for maximum burst length.", true, ConfigKey.Scope.Global, null); - public static final ConfigKey ADD_HOST_ON_SERVICE_RESTART_KVM = new ConfigKey(Boolean.class, "add.host.on.service.restart.kvm", "Advanced", "true", - "Indicates whether the host will be added back to cloudstack after restarting agent service on host. If false it won't be added back even after service restart", - true, ConfigKey.Scope.Global, null); - public static final ConfigKey SET_HOST_DOWN_TO_MAINTENANCE = new ConfigKey(Boolean.class, "set.host.down.to.maintenance", "Advanced", "false", - "Indicates whether the host in down state can be put into maintenance state so thats its not enabled after it comes back.", - true, ConfigKey.Scope.Zone, null); - public static final ConfigKey ENABLE_ACCOUNT_SETTINGS_FOR_DOMAIN = new ConfigKey(Boolean.class, "enable.account.settings.for.domain", "Advanced", "false", - "Indicates whether to add account settings for domain. If true, account settings will be added to domain settings, all accounts in the domain will inherit the domain setting if account setting is not set.", true, ConfigKey.Scope.Global, null); - public static final ConfigKey ENABLE_DOMAIN_SETTINGS_FOR_CHILD_DOMAIN = new ConfigKey(Boolean.class, "enable.domain.settings.for.child.domain", "Advanced", "false", - "Indicates whether the settings of parent domain should be applied for child domain. If true, the child domain will get value from parent domain if its not configured in child domain else global value is taken.", - true, ConfigKey.Scope.Global, null); - - public static ConfigKey VM_SERVICE_OFFERING_MAX_CPU_CORES = new ConfigKey("Advanced", Integer.class, "vm.serviceoffering.cpu.cores.max", "0", "Maximum CPU cores " - + "for vm service offering. If 0 - no limitation", true); - - public static ConfigKey VM_SERVICE_OFFERING_MAX_RAM_SIZE = new ConfigKey("Advanced", Integer.class, "vm.serviceoffering.ram.size.max", "0", "Maximum RAM size in " - + "MB for vm service offering. If 0 - no limitation", true); - - public static final ConfigKey VM_USERDATA_MAX_LENGTH = new ConfigKey("Advanced", Integer.class, VM_USERDATA_MAX_LENGTH_STRING, "32768", - "Max length of vm userdata after base64 decoding. Default is 32768 and maximum is 1048576", true); - public static final ConfigKey MIGRATE_VM_ACROSS_CLUSTERS = new ConfigKey(Boolean.class, "migrate.vm.across.clusters", "Advanced", "false", - "Indicates whether the VM can be migrated to different cluster if no host is found in same cluster",true, ConfigKey.Scope.Zone, null); private static final String IOPS_READ_RATE = "IOPS Read"; private static final String IOPS_WRITE_RATE = "IOPS Write"; @@ -494,10 +420,11 @@ public class ConfigurationManagerImpl extends ManagerBase implements Configurati private static final Set VPC_ONLY_PROVIDERS = Sets.newHashSet(Provider.VPCVirtualRouter, Provider.JuniperContrailVpcRouter, Provider.InternalLbVm); - private static final long GiB_TO_BYTES = 1024 * 1024 * 1024; - @Override public boolean configure(final String name, final Map params) throws ConfigurationException { + final String maxVolumeSizeInGbString = _configDao.getValue(Config.MaxVolumeSize.key()); + _maxVolumeSizeInGb = NumbersUtil.parseInt(maxVolumeSizeInGbString, Integer.parseInt(Config.MaxVolumeSize.getDefaultValue())); + final String defaultPageSizeString = _configDao.getValue(Config.DefaultPageSize.key()); _defaultPageSize = NumbersUtil.parseLong(defaultPageSizeString, Long.parseLong(Config.DefaultPageSize.getDefaultValue())); @@ -532,10 +459,6 @@ private void populateConfigValuesForValidationSet() { configValuesForValidation.add("externaldhcp.vmip.max.retry"); configValuesForValidation.add("externaldhcp.vmipFetch.threadPool.max"); configValuesForValidation.add("remote.access.vpn.psk.length"); - configValuesForValidation.add(StorageManager.STORAGE_POOL_DISK_WAIT.key()); - configValuesForValidation.add(StorageManager.STORAGE_POOL_CLIENT_TIMEOUT.key()); - configValuesForValidation.add(StorageManager.STORAGE_POOL_CLIENT_MAX_CONNECTIONS.key()); - configValuesForValidation.add(VM_USERDATA_MAX_LENGTH_STRING); } private void weightBasedParametersForValidation() { @@ -556,7 +479,6 @@ private void weightBasedParametersForValidation() { weightBasedParametersForValidation.add(DeploymentClusterPlanner.ClusterMemoryCapacityDisableThreshold.key()); weightBasedParametersForValidation.add(Config.AgentLoadThreshold.key()); weightBasedParametersForValidation.add(Config.VmUserDispersionWeight.key()); - weightBasedParametersForValidation.add(CapacityManager.SecondaryStorageCapacityThreshold.key()); } @@ -572,17 +494,15 @@ private void initMessageBusListener() { @Override public void onPublishMessage(String serderAddress, String subject, Object args) { String globalSettingUpdated = (String) args; - if (StringUtils.isEmpty(globalSettingUpdated)) { + if (Strings.isNullOrEmpty(globalSettingUpdated)) { return; } if (globalSettingUpdated.equals(ApiServiceConfiguration.ManagementServerAddresses.key()) || globalSettingUpdated.equals(IndirectAgentLBServiceImpl.IndirectAgentLBAlgorithm.key())) { _indirectAgentLB.propagateMSListToAgents(); - } else if (globalSettingUpdated.equals(Config.RouterAggregationCommandEachTimeout.toString()) - || globalSettingUpdated.equals(Config.MigrateWait.toString())) { + } else if (globalSettingUpdated.equals(Config.RouterAggregationCommandEachTimeout.toString())) { Map params = new HashMap(); params.put(Config.RouterAggregationCommandEachTimeout.toString(), _configDao.getValue(Config.RouterAggregationCommandEachTimeout.toString())); - params.put(Config.MigrateWait.toString(), _configDao.getValue(Config.MigrateWait.toString())); _agentManager.propagateChangeToAgents(params); } } @@ -639,94 +559,81 @@ public String updateConfiguration(final long userId, final String name, final St // global parameter updation if (scope != null && !scope.isEmpty() && !ConfigKey.Scope.Global.toString().equalsIgnoreCase(scope)) { switch (ConfigKey.Scope.valueOf(scope)) { - case Zone: - final DataCenterVO zone = _zoneDao.findById(resourceId); - if (zone == null) { - throw new InvalidParameterValueException("unable to find zone by id " + resourceId); - } - _dcDetailsDao.addDetail(resourceId, name, value, true); - break; - case Cluster: - final ClusterVO cluster = _clusterDao.findById(resourceId); - if (cluster == null) { - throw new InvalidParameterValueException("unable to find cluster by id " + resourceId); - } - String newName = name; - if (name.equalsIgnoreCase("cpu.overprovisioning.factor")) { - newName = "cpuOvercommitRatio"; - } - if (name.equalsIgnoreCase("mem.overprovisioning.factor")) { - newName = "memoryOvercommitRatio"; - } - ClusterDetailsVO clusterDetailsVO = _clusterDetailsDao.findDetail(resourceId, newName); - if (clusterDetailsVO == null) { - clusterDetailsVO = new ClusterDetailsVO(resourceId, newName, value); - _clusterDetailsDao.persist(clusterDetailsVO); - } else { - clusterDetailsVO.setValue(value); - _clusterDetailsDao.update(clusterDetailsVO.getId(), clusterDetailsVO); - } - break; - - case StoragePool: - final StoragePoolVO pool = _storagePoolDao.findById(resourceId); - if (pool == null) { - throw new InvalidParameterValueException("unable to find storage pool by id " + resourceId); - } - if(name.equals(CapacityManager.StorageOverprovisioningFactor.key())) { - if(!pool.getPoolType().supportsOverProvisioning() ) { - throw new InvalidParameterValueException("Unable to update storage pool with id " + resourceId + ". Overprovision not supported for " + pool.getPoolType()); + case Zone: + final DataCenterVO zone = _zoneDao.findById(resourceId); + if (zone == null) { + throw new InvalidParameterValueException("unable to find zone by id " + resourceId); } - } - - _storagePoolDetailsDao.addDetail(resourceId, name, value, true); - if (pool.getPoolType() == Storage.StoragePoolType.DatastoreCluster) { - List childDataStores = _storagePoolDao.listChildStoragePoolsInDatastoreCluster(resourceId); - for (StoragePoolVO childDataStore: childDataStores) { - _storagePoolDetailsDao.addDetail(childDataStore.getId(), name, value, true); + _dcDetailsDao.addDetail(resourceId, name, value, true); + break; + case Cluster: + final ClusterVO cluster = _clusterDao.findById(resourceId); + if (cluster == null) { + throw new InvalidParameterValueException("unable to find cluster by id " + resourceId); } - } + ClusterDetailsVO clusterDetailsVO = _clusterDetailsDao.findDetail(resourceId, name); + if (clusterDetailsVO == null) { + clusterDetailsVO = new ClusterDetailsVO(resourceId, name, value); + _clusterDetailsDao.persist(clusterDetailsVO); + } else { + clusterDetailsVO.setValue(value); + _clusterDetailsDao.update(clusterDetailsVO.getId(), clusterDetailsVO); + } + break; - break; + case StoragePool: + final StoragePoolVO pool = _storagePoolDao.findById(resourceId); + if (pool == null) { + throw new InvalidParameterValueException("unable to find storage pool by id " + resourceId); + } + if(name.equals(CapacityManager.StorageOverprovisioningFactor.key())) { + if(!pool.getPoolType().supportsOverProvisioning() ) { + throw new InvalidParameterValueException("Unable to update storage pool with id " + resourceId + ". Overprovision not supported for " + pool.getPoolType()); + } + } - case Account: - final AccountVO account = _accountDao.findById(resourceId); - if (account == null) { - throw new InvalidParameterValueException("unable to find account by id " + resourceId); - } - AccountDetailVO accountDetailVO = _accountDetailsDao.findDetail(resourceId, name); - if (accountDetailVO == null) { - accountDetailVO = new AccountDetailVO(resourceId, name, value); - _accountDetailsDao.persist(accountDetailVO); - } else { - accountDetailVO.setValue(value); - _accountDetailsDao.update(accountDetailVO.getId(), accountDetailVO); - } - break; + _storagePoolDetailsDao.addDetail(resourceId, name, value, true); - case ImageStore: - final ImageStoreVO imgStore = _imageStoreDao.findById(resourceId); - Preconditions.checkState(imgStore != null); - _imageStoreDetailsDao.addDetail(resourceId, name, value, true); - break; + break; - case Domain: - final DomainVO domain = _domainDao.findById(resourceId); - if (domain == null) { - throw new InvalidParameterValueException("unable to find domain by id " + resourceId); - } - DomainDetailVO domainDetailVO = _domainDetailsDao.findDetail(resourceId, name); - if (domainDetailVO == null) { - domainDetailVO = new DomainDetailVO(resourceId, name, value); - _domainDetailsDao.persist(domainDetailVO); - } else { - domainDetailVO.setValue(value); - _domainDetailsDao.update(domainDetailVO.getId(), domainDetailVO); - } - break; + case Account: + final AccountVO account = _accountDao.findById(resourceId); + if (account == null) { + throw new InvalidParameterValueException("unable to find account by id " + resourceId); + } + AccountDetailVO accountDetailVO = _accountDetailsDao.findDetail(resourceId, name); + if (accountDetailVO == null) { + accountDetailVO = new AccountDetailVO(resourceId, name, value); + _accountDetailsDao.persist(accountDetailVO); + } else { + accountDetailVO.setValue(value); + _accountDetailsDao.update(accountDetailVO.getId(), accountDetailVO); + } + break; + + case ImageStore: + final ImageStoreVO imgStore = _imageStoreDao.findById(resourceId); + Preconditions.checkState(imgStore != null); + _imageStoreDetailsDao.addDetail(resourceId, name, value, true); + break; + + case Domain: + final DomainVO domain = _domainDao.findById(resourceId); + if (domain == null) { + throw new InvalidParameterValueException("unable to find domain by id " + resourceId); + } + DomainDetailVO domainDetailVO = _domainDetailsDao.findDetail(resourceId, name); + if (domainDetailVO == null) { + domainDetailVO = new DomainDetailVO(resourceId, name, value); + _domainDetailsDao.persist(domainDetailVO); + } else { + domainDetailVO.setValue(value); + _domainDetailsDao.update(domainDetailVO.getId(), domainDetailVO); + } + break; - default: - throw new InvalidParameterValueException("Scope provided is invalid"); + default: + throw new InvalidParameterValueException("Scope provided is invalid"); } return value; } @@ -831,25 +738,14 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP final Long zoneId = cmd.getZoneId(); final Long clusterId = cmd.getClusterId(); final Long storagepoolId = cmd.getStoragepoolId(); + final Long accountId = cmd.getAccountId(); final Long imageStoreId = cmd.getImageStoreId(); - Long accountId = cmd.getAccountId(); - Long domainId = cmd.getDomainId(); + final Long domainId = cmd.getDomainId(); CallContext.current().setEventDetails(" Name: " + name + " New Value: " + (name.toLowerCase().contains("password") ? "*****" : value == null ? "" : value)); // check if config value exists final ConfigurationVO config = _configDao.findByName(name); String catergory = null; - final Account caller = CallContext.current().getCallingAccount(); - if (_accountMgr.isDomainAdmin(caller.getId())) { - if (accountId == null && domainId == null) { - domainId = caller.getDomainId(); - } - } else if (_accountMgr.isNormalUser(caller.getId())) { - if (accountId == null) { - accountId = caller.getAccountId(); - } - } - // FIX ME - All configuration parameters are not moved from config.java to configKey if (config == null) { if (_configDepot.get(name) == null) { @@ -865,6 +761,12 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP return _configDao.findByName(name); } + value = value.trim(); + + if (value.isEmpty() || value.equals("null")) { + value = null; + } + String scope = null; Long id = null; int paramCountCheck = 0; @@ -880,14 +782,11 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP paramCountCheck++; } if (accountId != null) { - Account account = _accountMgr.getAccount(accountId); - _accountMgr.checkAccess(caller, null, false, account); scope = ConfigKey.Scope.Account.toString(); id = accountId; paramCountCheck++; } if (domainId != null) { - _accountMgr.checkAccess(caller, _domainDao.findById(domainId)); scope = ConfigKey.Scope.Domain.toString(); id = domainId; paramCountCheck++; @@ -907,12 +806,6 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP throw new InvalidParameterValueException("cannot handle multiple IDs, provide only one ID corresponding to the scope"); } - value = value.trim(); - - if (value.isEmpty() || value.equals("null")) { - value = (id == null) ? null : ""; - } - final String updatedValue = updateConfiguration(userId, name, catergory, value, scope, id); if (value == null && updatedValue == null || updatedValue.equalsIgnoreCase(value)) { return _configDao.findByName(name); @@ -921,170 +814,6 @@ public Configuration updateConfiguration(final UpdateCfgCmd cmd) throws InvalidP } } - private ParamCountPair getParamCount(Map scopeMap) { - Long id = null; - int paramCount = 0; - String scope = ConfigKey.Scope.Global.toString(); - - for (var entry : scopeMap.entrySet()) { - if (entry.getValue() != null) { - id = entry.getValue(); - scope = entry.getKey(); - paramCount++; - } - } - - return new ParamCountPair(id, paramCount, scope); - } - - @Override - @ActionEvent(eventType = EventTypes.EVENT_CONFIGURATION_VALUE_EDIT, eventDescription = "resetting configuration") - public Pair resetConfiguration(final ResetCfgCmd cmd) throws InvalidParameterValueException { - final Long userId = CallContext.current().getCallingUserId(); - final String name = cmd.getCfgName(); - final Long zoneId = cmd.getZoneId(); - final Long clusterId = cmd.getClusterId(); - final Long storagepoolId = cmd.getStoragepoolId(); - final Long accountId = cmd.getAccountId(); - final Long domainId = cmd.getDomainId(); - final Long imageStoreId = cmd.getImageStoreId(); - ConfigKey configKey = null; - Optional optionalValue; - String defaultValue; - String category; - String configScope; - final ConfigurationVO config = _configDao.findByName(name); - if (config == null) { - configKey = _configDepot.get(name); - if (configKey == null) { - s_logger.warn("Probably the component manager where configuration variable " + name + " is defined needs to implement Configurable interface"); - throw new InvalidParameterValueException("Config parameter with name " + name + " doesn't exist"); - } - defaultValue = configKey.defaultValue(); - category = configKey.category(); - configScope = configKey.scope().toString(); - } else { - defaultValue = config.getDefaultValue(); - category = config.getCategory(); - configScope = config.getScope(); - } - - String scope = ""; - Map scopeMap = new LinkedHashMap<>(); - - Long id = null; - int paramCountCheck = 0; - - scopeMap.put(ConfigKey.Scope.Zone.toString(), zoneId); - scopeMap.put(ConfigKey.Scope.Cluster.toString(), clusterId); - scopeMap.put(ConfigKey.Scope.Domain.toString(), domainId); - scopeMap.put(ConfigKey.Scope.Account.toString(), accountId); - scopeMap.put(ConfigKey.Scope.StoragePool.toString(), storagepoolId); - scopeMap.put(ConfigKey.Scope.ImageStore.toString(), imageStoreId); - - ParamCountPair paramCountPair = getParamCount(scopeMap); - id = paramCountPair.getId(); - paramCountCheck = paramCountPair.getParamCount(); - scope = paramCountPair.getScope(); - - if (paramCountCheck > 1) { - throw new InvalidParameterValueException("cannot handle multiple IDs, provide only one ID corresponding to the scope"); - } - - if (scope != null && !scope.equals(ConfigKey.Scope.Global.toString()) && !configScope.contains(scope)) { - throw new InvalidParameterValueException("Invalid scope id provided for the parameter " + name); - } - - String newValue = null; - switch (ConfigKey.Scope.valueOf(scope)) { - case Zone: - final DataCenterVO zone = _zoneDao.findById(id); - if (zone == null) { - throw new InvalidParameterValueException("unable to find zone by id " + id); - } - _dcDetailsDao.removeDetail(id, name); - optionalValue = Optional.ofNullable(configKey != null ? configKey.valueIn(id): config.getValue()); - newValue = optionalValue.isPresent() ? optionalValue.get().toString() : defaultValue; - break; - - case Cluster: - final ClusterVO cluster = _clusterDao.findById(id); - if (cluster == null) { - throw new InvalidParameterValueException("unable to find cluster by id " + id); - } - ClusterDetailsVO clusterDetailsVO = _clusterDetailsDao.findDetail(id, name); - newValue = configKey != null ? configKey.value().toString() : config.getValue(); - if (name.equalsIgnoreCase("cpu.overprovisioning.factor") || name.equalsIgnoreCase("mem.overprovisioning.factor")) { - _clusterDetailsDao.persist(id, name, newValue); - } else if (clusterDetailsVO != null) { - _clusterDetailsDao.remove(clusterDetailsVO.getId()); - } - optionalValue = Optional.ofNullable(configKey != null ? configKey.valueIn(id): config.getValue()); - newValue = optionalValue.isPresent() ? optionalValue.get().toString() : defaultValue; - break; - - case StoragePool: - final StoragePoolVO pool = _storagePoolDao.findById(id); - if (pool == null) { - throw new InvalidParameterValueException("unable to find storage pool by id " + id); - } - _storagePoolDetailsDao.removeDetail(id, name); - optionalValue = Optional.ofNullable(configKey != null ? configKey.valueIn(id) : config.getValue()); - newValue = optionalValue.isPresent() ? optionalValue.get().toString() : defaultValue; - break; - - case Domain: - final DomainVO domain = _domainDao.findById(id); - if (domain == null) { - throw new InvalidParameterValueException("unable to find domain by id " + id); - } - DomainDetailVO domainDetailVO = _domainDetailsDao.findDetail(id, name); - if (domainDetailVO != null) { - _domainDetailsDao.remove(domainDetailVO.getId()); - } - optionalValue = Optional.ofNullable(configKey != null ? configKey.valueIn(id) : config.getValue()); - newValue = optionalValue.isPresent() ? optionalValue.get().toString() : defaultValue; - break; - - case Account: - final AccountVO account = _accountDao.findById(id); - if (account == null) { - throw new InvalidParameterValueException("unable to find account by id " + id); - } - AccountDetailVO accountDetailVO = _accountDetailsDao.findDetail(id, name); - if (accountDetailVO != null) { - _accountDetailsDao.remove(accountDetailVO.getId()); - } - optionalValue = Optional.ofNullable(configKey != null ? configKey.valueIn(id) : config.getValue()); - newValue = optionalValue.isPresent() ? optionalValue.get().toString() : defaultValue; - break; - - case ImageStore: - final ImageStoreVO imageStoreVO = _imageStoreDao.findById(id); - if (imageStoreVO == null) { - throw new InvalidParameterValueException("unable to find the image store by id " + id); - } - ImageStoreDetailVO imageStoreDetailVO = _imageStoreDetailsDao.findDetail(id, name); - if (imageStoreDetailVO != null) { - _imageStoreDetailsDao.remove(imageStoreDetailVO.getId()); - } - optionalValue = Optional.ofNullable(configKey != null ? configKey.valueIn(id) : config.getValue()); - newValue = optionalValue.isPresent() ? optionalValue.get().toString() : defaultValue; - break; - - default: - if (!_configDao.update(name, category, defaultValue)) { - s_logger.error("Failed to reset configuration option, name: " + name + ", defaultValue:" + defaultValue); - throw new CloudRuntimeException("Failed to reset configuration value. Please contact Cloud Support."); - } - optionalValue = Optional.ofNullable(configKey != null ? configKey.value() : _configDao.findByName(name).getValue()); - newValue = optionalValue.isPresent() ? optionalValue.get().toString() : defaultValue; - } - - CallContext.current().setEventDetails(" Name: " + name + " New Value: " + (name.toLowerCase().contains("password") ? "*****" : defaultValue == null ? "" : defaultValue)); - return new Pair(_configDao.findByName(name), newValue); - } - private String validateConfigurationValue(final String name, String value, final String scope) { final ConfigurationVO cfg = _configDao.findByName(name); @@ -1095,9 +824,7 @@ private String validateConfigurationValue(final String name, String value, final final String configScope = cfg.getScope(); if (scope != null) { - if (!configScope.contains(scope) && - !(ENABLE_ACCOUNT_SETTINGS_FOR_DOMAIN.value() && configScope.contains(ConfigKey.Scope.Account.toString()) && - scope.equals(ConfigKey.Scope.Domain.toString()))) { + if (!configScope.contains(scope)) { s_logger.error("Invalid scope id provided for the parameter " + name); return "Invalid scope id provided for the parameter " + name; } @@ -1149,8 +876,8 @@ private String validateConfigurationValue(final String name, String value, final value = value.trim(); try { - if (overprovisioningFactorsForValidation.contains(name) && Float.parseFloat(value) <= 0f) { - final String msg = name + " should be greater than 0"; + if (overprovisioningFactorsForValidation.contains(name) && Float.parseFloat(value) < 1f) { + final String msg = name + " should be greater than or equal to 1"; s_logger.error(msg); throw new InvalidParameterValueException(msg); } @@ -1199,11 +926,6 @@ private String validateConfigurationValue(final String name, String value, final throw new InvalidParameterValueException("Please enter a value less than 257 for the configuration parameter:" + name); } } - if (VM_USERDATA_MAX_LENGTH_STRING.equalsIgnoreCase(name)) { - if (val > 1048576) { - throw new InvalidParameterValueException("Please enter a value less than 1048576 for the configuration parameter:" + name); - } - } } catch (final NumberFormatException e) { s_logger.error("There was an error trying to parse the integer value for:" + name); throw new InvalidParameterValueException("There was an error trying to parse the integer value for:" + name); @@ -1278,7 +1000,7 @@ private String validateConfigurationValue(final String name, String value, final if (route != null) { final String routeToVerify = route.trim(); if (!NetUtils.isValidIp4Cidr(routeToVerify)) { - throw new InvalidParameterValueException("Invalid value for route: " + route + " in deny list. Valid format is list" + throw new InvalidParameterValueException("Invalid value for blacklisted route: " + route + ". Valid format is list" + " of cidrs separated by coma. Example: 10.1.1.0/24,192.168.0.0/24"); } } @@ -1350,7 +1072,7 @@ protected void checkIfPodIsDeletable(final long podId) { } private void checkPodAttributes(final long podId, final String podName, final long zoneId, final String gateway, final String cidr, final String startIp, final String endIp, final String allocationStateStr, - final boolean checkForDuplicates, final boolean skipGatewayOverlapCheck) { + final boolean checkForDuplicates, final boolean skipGatewayOverlapCheck) { if (checkForDuplicates) { // Check if the pod already exists if (validPod(podName, zoneId)) { @@ -1373,7 +1095,7 @@ private void checkPodAttributes(final long podId, final String podName, final lo checkIpRange(startIp, endIp, cidrAddress, cidrSize); // Check if the IP range overlaps with the public ip - if(StringUtils.isNotEmpty(startIp)) { + if(!Strings.isNullOrEmpty(startIp)) { checkOverlapPublicIpRange(zoneId, startIp, endIp); } @@ -1410,7 +1132,6 @@ private void checkPodAttributes(final long podId, final String podName, final lo @Override @DB - @ActionEvent(eventType = EventTypes.EVENT_POD_DELETE, eventDescription = "deleting pod", async = false) public boolean deletePod(final DeletePodCmd cmd) { final Long podId = cmd.getId(); @@ -1463,9 +1184,6 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { if (dr != null) { _dedicatedDao.remove(dr.getId()); } - - // Remove comments (if any) - annotationDao.removeByEntityType(AnnotationService.EntityType.POD.name(), pod.getUuid()); } }); @@ -1508,7 +1226,7 @@ public Pod createPodIpRange(final CreateManagementNetworkIpRangeCmd cmd) { String endIp = cmd.getEndIp(); final boolean forSystemVms = cmd.isForSystemVms(); String vlan = cmd.getVlan(); - if (StringUtils.isNotEmpty(vlan) && !vlan.startsWith(BroadcastDomainType.Vlan.scheme())) { + if (!(Strings.isNullOrEmpty(vlan) || vlan.startsWith(BroadcastDomainType.Vlan.scheme()))) { vlan = BroadcastDomainType.Vlan.toUri(vlan).toString(); } @@ -1523,7 +1241,7 @@ public Pod createPodIpRange(final CreateManagementNetworkIpRangeCmd cmd) { final long zoneId = pod.getDataCenterId(); - if(!NetUtils.isValidIp4(gateway) && !NetUtils.isValidIp6(gateway)) { + if(!NetUtils.isValidIp4(gateway)) { throw new InvalidParameterValueException("The gateway IP address is invalid."); } @@ -1595,7 +1313,7 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { /* * POD Description is refactored to: * ---,---,... - */ + */ String range = startIp + "-" + endIpFinal + "-" + (forSystemVms ? "1" : "0") + "-" + (vlanId == null ? DefaultVlanForPodIpRange : vlanId); if(ipRange != null && !ipRange.isEmpty()) ipRange += ("," + range); @@ -1746,256 +1464,6 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { } @Override - @DB - public void updatePodIpRange(final UpdatePodManagementNetworkIpRangeCmd cmd) throws ConcurrentOperationException { - final long podId = cmd.getPodId(); - final HostPodVO pod = _podDao.findById(podId); - if (pod == null) { - throw new InvalidParameterValueException("Unable to find pod by id: " + podId); - } - - final String currentStartIP = cmd.getCurrentStartIP(); - final String currentEndIP = cmd.getCurrentEndIP(); - String newStartIP = cmd.getNewStartIP(); - String newEndIP = cmd.getNewEndIP(); - - if (newStartIP == null) { - newStartIP = currentStartIP; - } - - if (newEndIP == null) { - newEndIP = currentEndIP; - } - - if (newStartIP.equals(currentStartIP) && newEndIP.equals(currentEndIP)) { - throw new InvalidParameterValueException("New starting and ending IP address are the same as current starting and ending IP address"); - } - - final String[] existingPodIpRanges = pod.getDescription().split(","); - if (existingPodIpRanges.length == 0) { - throw new InvalidParameterValueException("The IP range cannot be found in the pod: " + podId + " since the existing IP range is empty."); - } - - verifyIpRangeParameters(currentStartIP,currentEndIP); - verifyIpRangeParameters(newStartIP,newEndIP); - checkIpRangeContainsTakenAddresses(pod,currentStartIP,currentEndIP,newStartIP,newEndIP); - - String vlan = verifyPodIpRangeExists(podId,existingPodIpRanges,currentStartIP,currentEndIP,newStartIP,newEndIP); - - List currentIpRange = listAllIPsWithintheRange(currentStartIP,currentEndIP); - List newIpRange = listAllIPsWithintheRange(newStartIP,newEndIP); - - try { - final String finalNewEndIP = newEndIP; - final String finalNewStartIP = newStartIP; - final Integer vlanId = vlan.equals(Vlan.UNTAGGED) ? null : Integer.parseInt(vlan); - - Transaction.execute(new TransactionCallbackNoReturn() { - @Override - public void doInTransactionWithoutResult(final TransactionStatus status) { - final long zoneId = pod.getDataCenterId(); - pod.setDescription(pod.getDescription().replace(currentStartIP + "-", - finalNewStartIP + "-").replace(currentEndIP, finalNewEndIP)); - updatePodIpRangeInDb(zoneId,podId,vlanId,pod,newIpRange,currentIpRange); - } - }); - } catch (final Exception e) { - s_logger.error("Unable to update Pod " + podId + " IP range due to " + e.getMessage(), e); - throw new CloudRuntimeException("Failed to update Pod " + podId + " IP range. Please contact Cloud Support."); - } - } - - private String verifyPodIpRangeExists(long podId,String[] existingPodIpRanges, String currentStartIP, - String currentEndIP, String newStartIP, String newEndIP) { - boolean foundRange = false; - String vlan = null; - - for (String podIpRange: existingPodIpRanges) { - final String[] existingPodIpRange = podIpRange.split("-"); - - if (existingPodIpRange.length > 1) { - if (!NetUtils.isValidIp4(existingPodIpRange[0]) || !NetUtils.isValidIp4(existingPodIpRange[1])) { - continue; - } - if (currentStartIP.equals(existingPodIpRange[0]) && currentEndIP.equals(existingPodIpRange[1])) { - foundRange = true; - vlan = existingPodIpRange[3]; - } - if (!foundRange && NetUtils.ipRangesOverlap(newStartIP, newEndIP, existingPodIpRange[0], existingPodIpRange[1])) { - throw new InvalidParameterValueException("The Start and End IP address range: (" + newStartIP + "-" + newEndIP + ") overlap with the pod IP range: " + podIpRange); - } - } - } - - if (!foundRange) { - throw new InvalidParameterValueException("The input IP range: " + currentStartIP + "-" + currentEndIP + " of pod: " + podId + " is not present. Please input an existing range."); - } - - return vlan; - } - - private void updatePodIpRangeInDb (long zoneId, long podId, Integer vlanId, HostPodVO pod, List newIpRange, List currentIpRange) { - HostPodVO lock = null; - try { - lock = _podDao.acquireInLockTable(podId); - if (lock == null) { - String msg = "Unable to acquire lock on table to update the ip range of POD: " + pod.getName() + ", Update failed."; - s_logger.warn(msg); - throw new CloudRuntimeException(msg); - } - List iPaddressesToAdd = new ArrayList(newIpRange); - iPaddressesToAdd.removeAll(currentIpRange); - if (iPaddressesToAdd.size() > 0) { - for (Long startIP : iPaddressesToAdd) { - _zoneDao.addPrivateIpAddress(zoneId, podId, NetUtils.long2Ip(startIP), NetUtils.long2Ip(startIP), false, vlanId); - } - } else { - currentIpRange.removeAll(newIpRange); - if (currentIpRange.size() > 0) { - for (Long startIP: currentIpRange) { - if (!_privateIpAddressDao.deleteIpAddressByPodDc(NetUtils.long2Ip(startIP),podId,zoneId)) { - throw new CloudRuntimeException("Failed to remove private ip address: " + NetUtils.long2Ip(startIP) + " of Pod: " + podId + " DC: " + pod.getDataCenterId()); - } - } - } - } - _podDao.update(podId, pod); - } catch (final Exception e) { - s_logger.error("Unable to update Pod " + podId + " IP range due to database error " + e.getMessage(), e); - throw new CloudRuntimeException("Failed to update Pod " + podId + " IP range. Please contact Cloud Support."); - } finally { - if (lock != null) { - _podDao.releaseFromLockTable(podId); - } - } - } - - private List listAllIPsWithintheRange(String startIp, String endIP) { - verifyIpRangeParameters(startIp,endIP); - long startIpLong = NetUtils.ip2Long(startIp); - long endIpLong = NetUtils.ip2Long(endIP); - - List listOfIpsinRange = new ArrayList<>(); - while (startIpLong <= endIpLong) { - listOfIpsinRange.add(startIpLong); - startIpLong++; - } - return listOfIpsinRange; - } - - private void verifyIpRangeParameters(String startIP, String endIp) { - - if (StringUtils.isNotEmpty(startIP) && !NetUtils.isValidIp4(startIP)) { - throw new InvalidParameterValueException("The current start address of the IP range " + startIP + " is not a valid IP address."); - } - - if (StringUtils.isNotEmpty(endIp) && !NetUtils.isValidIp4(endIp)) { - throw new InvalidParameterValueException("The current end address of the IP range " + endIp + " is not a valid IP address."); - } - - if (NetUtils.ip2Long(startIP) > NetUtils.ip2Long(endIp)) { - throw new InvalidParameterValueException("The start IP address must have a lower value than the end IP address."); - } - } - - private void checkIpRangeContainsTakenAddresses(final HostPodVO pod,final String currentStartIP, - final String currentEndIP,final String newStartIp, final String newEndIp) { - - List newIpRange = listAllIPsWithintheRange(newStartIp,newEndIp); - List currentIpRange = listAllIPsWithintheRange(currentStartIP,currentEndIP); - List takenIpsList = new ArrayList<>(); - final List takenIps = _privateIpAddressDao.listIpAddressUsage(pod.getId(),pod.getDataCenterId(),true); - - for (DataCenterIpAddressVO takenIp : takenIps) { - takenIpsList.add(NetUtils.ip2Long(takenIp.getIpAddress())); - } - - takenIpsList.retainAll(currentIpRange); - if (!newIpRange.containsAll(takenIpsList)) { - throw new InvalidParameterValueException("The IP range does not contain some IP addresses that have " - + "already been taken. Please adjust your IP range to include all IP addresses already taken."); - } - } - - @Override - @DB - public DataCenterGuestIpv6Prefix createDataCenterGuestIpv6Prefix(final CreateGuestNetworkIpv6PrefixCmd cmd) throws ConcurrentOperationException { - final long zoneId = cmd.getZoneId(); - final DataCenterVO zone = _zoneDao.findById(zoneId); - if (zone == null) { - throw new InvalidParameterValueException("Unable to find zone by id: " + zoneId); - } - final String prefix = cmd.getPrefix(); - IPv6Network prefixNet = IPv6Network.fromString(prefix); - if (prefixNet.getNetmask().asPrefixLength() > Ipv6Service.IPV6_SLAAC_CIDR_NETMASK) { - throw new InvalidParameterValueException(String.format("IPv6 prefix must be /%d or less", Ipv6Service.IPV6_SLAAC_CIDR_NETMASK)); - } - List existingPrefixes = dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId); - for (DataCenterGuestIpv6PrefixVO existingPrefix : existingPrefixes) { - IPv6Network existingPrefixNet = IPv6Network.fromString(existingPrefix.getPrefix()); - if (NetUtils.ipv6NetworksOverlap(existingPrefixNet, prefixNet)) { - throw new InvalidParameterValueException(String.format("IPv6 prefix %s overlaps with the existing IPv6 prefix %s", prefixNet, existingPrefixNet)); - } - } - DataCenterGuestIpv6Prefix dataCenterGuestIpv6Prefix = null; - try { - dataCenterGuestIpv6Prefix = Transaction.execute(new TransactionCallback() { - @Override - public DataCenterGuestIpv6Prefix doInTransaction(TransactionStatus status) { - DataCenterGuestIpv6PrefixVO dataCenterGuestIpv6PrefixVO = new DataCenterGuestIpv6PrefixVO(zoneId, prefix); - dataCenterGuestIpv6PrefixDao.persist(dataCenterGuestIpv6PrefixVO); - return dataCenterGuestIpv6PrefixVO; - } - }); - } catch (final Exception e) { - s_logger.error(String.format("Unable to add IPv6 prefix for zone: %s due to %s", zone, e.getMessage()), e); - throw new CloudRuntimeException(String.format("Unable to add IPv6 prefix for zone ID: %s. Please contact Cloud Support.", zone.getUuid())); - } - return dataCenterGuestIpv6Prefix; - } - - @Override - public List listDataCenterGuestIpv6Prefixes(final ListGuestNetworkIpv6PrefixesCmd cmd) throws ConcurrentOperationException { - final Long id = cmd.getId(); - final Long zoneId = cmd.getZoneId(); - if (id != null) { - DataCenterGuestIpv6PrefixVO prefix = dataCenterGuestIpv6PrefixDao.findById(id); - List prefixes = new ArrayList<>(); - if (prefix != null) { - prefixes.add(prefix); - } - return prefixes; - } - if (zoneId != null) { - final DataCenterVO zone = _zoneDao.findById(zoneId); - if (zone == null) { - throw new InvalidParameterValueException("Unable to find zone by id: " + zoneId); - } - return dataCenterGuestIpv6PrefixDao.listByDataCenterId(zoneId); - } - return dataCenterGuestIpv6PrefixDao.listAll(); - } - - @Override - public boolean deleteDataCenterGuestIpv6Prefix(DeleteGuestNetworkIpv6PrefixCmd cmd) { - final long prefixId = cmd.getId(); - final DataCenterGuestIpv6PrefixVO prefix = dataCenterGuestIpv6PrefixDao.findById(prefixId); - if (prefix == null) { - throw new InvalidParameterValueException("Unable to find guest network IPv6 prefix by id: " + prefixId); - } - List prefixSubnets = ipv6GuestPrefixSubnetNetworkMapDao.listUsedByPrefix(prefixId); - if (CollectionUtils.isNotEmpty(prefixSubnets)) { - List usedSubnets = prefixSubnets.stream().map(Ipv6GuestPrefixSubnetNetworkMapVO::getSubnet).collect(Collectors.toList()); - s_logger.error(String.format("Subnets for guest IPv6 prefix {ID: %s, %s} are in use: %s", prefix.getUuid(), prefix.getPrefix(), String.join(", ", usedSubnets))); - throw new CloudRuntimeException(String.format("Unable to delete guest network IPv6 prefix ID: %s. Prefix subnets are in use.", prefix.getUuid())); - } - ipv6GuestPrefixSubnetNetworkMapDao.deleteByPrefixId(prefixId); - dataCenterGuestIpv6PrefixDao.remove(prefixId); - return true; - } - - @Override - @ActionEvent(eventType = EventTypes.EVENT_POD_EDIT, eventDescription = "updating pod", async = false) public Pod editPod(final UpdatePodCmd cmd) { return editPod(cmd.getId(), cmd.getPodName(), null, null, cmd.getGateway(), cmd.getNetmask(), cmd.getAllocationState()); } @@ -2015,7 +1483,7 @@ public Pod editPod(final long id, String name, String startIp, String endIp, Str // pod has allocated private IP addresses if (podHasAllocatedPrivateIPs(id)) { - if (StringUtils.isNotEmpty(netmask)) { + if (!Strings.isNullOrEmpty(netmask)) { final long newCidr = NetUtils.getCidrSize(netmask); final long oldCidr = pod.getCidrSize(); @@ -2109,7 +1577,6 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { } @Override - @ActionEvent(eventType = EventTypes.EVENT_POD_CREATE, eventDescription = "creating pod", async = false) public Pod createPod(final long zoneId, final String name, final String startIp, final String endIp, final String gateway, final String netmask, String allocationState) { // Check if the gateway is a valid IP address if (!NetUtils.isValidIp4(gateway)) { @@ -2133,7 +1600,7 @@ public Pod createPod(final long zoneId, final String name, final String startIp, @Override @DB public HostPodVO createPod(final long userId, final String podName, final long zoneId, final String gateway, final String cidr, final String startIp, String endIp, final String allocationStateStr, - final boolean skipGatewayOverlapCheck) { + final boolean skipGatewayOverlapCheck) { // Check if the zone is valid if (!validZone(zoneId)) { @@ -2153,7 +1620,7 @@ public HostPodVO createPod(final long userId, final String podName, final long z // endIp is an optional parameter; if not specified - default it to the // end ip of the pod's cidr - if (StringUtils.isNotEmpty(startIp)) { + if (!Strings.isNullOrEmpty(startIp)) { if (endIp == null) { endIp = NetUtils.getIpRangeEndIpFromCidr(cidrAddress, cidrSize); } @@ -2165,7 +1632,7 @@ public HostPodVO createPod(final long userId, final String podName, final long z // Create the new pod in the database String ipRange; - if (StringUtils.isNotEmpty(startIp)) { + if (!Strings.isNullOrEmpty(startIp)) { ipRange = startIp + "-" + endIp + "-" + DefaultForSystemVmsForPodIpRange + "-" + DefaultVlanForPodIpRange; } else { throw new InvalidParameterValueException("Start ip is required parameter"); @@ -2186,7 +1653,7 @@ public HostPodVO doInTransaction(final TransactionStatus status) { final HostPodVO pod = _podDao.persist(podFinal); - if (StringUtils.isNotEmpty(startIp)) { + if (!Strings.isNullOrEmpty(startIp)) { _zoneDao.addPrivateIpAddress(zoneId, pod.getId(), startIp, endIpFinal, false, null); } @@ -2195,8 +1662,6 @@ public HostPodVO doInTransaction(final TransactionStatus status) { _zoneDao.addLinkLocalIpAddress(zoneId, pod.getId(), linkLocalIpRanges[0], linkLocalIpRanges[1]); } - CallContext.current().putContextParameter(Pod.class, pod.getUuid()); - return pod; } }); @@ -2243,7 +1708,7 @@ protected void checkIfZoneIsDeletable(final long zoneId) { } //check if there are any secondary stores attached to the zone - if(!_imageStoreDao.findByZone(new ZoneScope(zoneId), null).isEmpty()) { + if(!_imageStoreDao.findByScope(new ZoneScope(zoneId)).isEmpty()) { throw new CloudRuntimeException(errorMsg + "there are Secondary storages in this zone"); } @@ -2254,7 +1719,7 @@ protected void checkIfZoneIsDeletable(final long zoneId) { } private void checkZoneParameters(final String zoneName, final String dns1, final String dns2, final String internalDns1, final String internalDns2, final boolean checkForDuplicates, final Long domainId, - final String allocationStateStr, final String ip6Dns1, final String ip6Dns2) { + final String allocationStateStr, final String ip6Dns1, final String ip6Dns2) { if (checkForDuplicates) { // Check if a zone with the specified name already exists if (validZone(zoneName)) { @@ -2309,24 +1774,24 @@ private void checkZoneParameters(final String zoneName, final String dns1, final private void checkIpRange(final String startIp, final String endIp, final String cidrAddress, final long cidrSize) { //Checking not null for start IP as well. Previously we assumed to be not null always. //But the check is required for the change in updatePod API. - if (StringUtils.isNotEmpty(startIp) && !NetUtils.isValidIp4(startIp)) { + if (!Strings.isNullOrEmpty(startIp) && !NetUtils.isValidIp4(startIp)) { throw new InvalidParameterValueException("The start address of the IP range is not a valid IP address."); } - if (StringUtils.isNotEmpty(endIp) && !NetUtils.isValidIp4(endIp)) { + if (!Strings.isNullOrEmpty(endIp) && !NetUtils.isValidIp4(endIp)) { throw new InvalidParameterValueException("The end address of the IP range is not a valid IP address."); } //Not null check is required for the change in updatePod API. - if (StringUtils.isNotEmpty(startIp) && !NetUtils.getCidrSubNet(startIp, cidrSize).equalsIgnoreCase(NetUtils.getCidrSubNet(cidrAddress, cidrSize))) { + if (!Strings.isNullOrEmpty(startIp) && !NetUtils.getCidrSubNet(startIp, cidrSize).equalsIgnoreCase(NetUtils.getCidrSubNet(cidrAddress, cidrSize))) { throw new InvalidParameterValueException("The start address of the IP range is not in the CIDR subnet."); } - if (StringUtils.isNotEmpty(endIp) && !NetUtils.getCidrSubNet(endIp, cidrSize).equalsIgnoreCase(NetUtils.getCidrSubNet(cidrAddress, cidrSize))) { + if (!Strings.isNullOrEmpty(endIp) && !NetUtils.getCidrSubNet(endIp, cidrSize).equalsIgnoreCase(NetUtils.getCidrSubNet(cidrAddress, cidrSize))) { throw new InvalidParameterValueException("The end address of the IP range is not in the CIDR subnet."); } - if (StringUtils.isNotEmpty(endIp) && NetUtils.ip2Long(startIp) > NetUtils.ip2Long(endIp)) { + if (!Strings.isNullOrEmpty(endIp) && NetUtils.ip2Long(startIp) > NetUtils.ip2Long(endIp)) { throw new InvalidParameterValueException("The start IP address must have a lower value than the end IP address."); } @@ -2373,7 +1838,6 @@ private void checkOverlapPrivateIpRange(final Long zoneId, final String startIp, public boolean deleteZone(final DeleteZoneCmd cmd) { final Long zoneId = cmd.getId(); - DataCenterVO zone = _zoneDao.findById(zoneId); // Make sure the zone exists if (!validZone(zoneId)) { @@ -2410,7 +1874,6 @@ public Boolean doInTransaction(final TransactionStatus status) { _affinityGroupService.deleteAffinityGroup(dr.getAffinityGroupId(), null, null, null, null); } } - annotationDao.removeByEntityType(AnnotationService.EntityType.ZONE.name(), zone.getUuid()); } return success; @@ -2640,8 +2103,8 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { @Override @DB public DataCenterVO createZone(final long userId, final String zoneName, final String dns1, final String dns2, final String internalDns1, final String internalDns2, final String guestCidr, final String domain, - final Long domainId, final NetworkType zoneType, final String allocationStateStr, final String networkDomain, final boolean isSecurityGroupEnabled, final boolean isLocalStorageEnabled, - final String ip6Dns1, final String ip6Dns2) { + final Long domainId, final NetworkType zoneType, final String allocationStateStr, final String networkDomain, final boolean isSecurityGroupEnabled, final boolean isLocalStorageEnabled, + final String ip6Dns1, final String ip6Dns2) { // checking the following params outside checkzoneparams method as we do // not use these params for updatezone @@ -2856,12 +2319,12 @@ public ServiceOffering createServiceOffering(final CreateServiceOfferingCmd cmd) throw new InvalidParameterValueException("For creating a custom compute offering cpu and memory all should be null"); } // if any of them is null, then all of them shoull be null - if (maxCPU == null || minCPU == null || maxMemory == null || minMemory == null || cpuSpeed == null) { - if (maxCPU != null || minCPU != null || maxMemory != null || minMemory != null || cpuSpeed != null) { - throw new InvalidParameterValueException("For creating a custom compute offering min/max cpu and min/max memory/cpu speed should all be null or all specified"); + if (maxCPU == null || minCPU == null || maxMemory == null || minMemory == null) { + if (maxCPU != null || minCPU != null || maxMemory != null || minMemory != null) { + throw new InvalidParameterValueException("For creating a custom compute offering min/max cpu and min/max memory should all be specified"); } } else { - if (cpuSpeed.intValue() < 0 || cpuSpeed.longValue() > Integer.MAX_VALUE) { + if (cpuSpeed != null && (cpuSpeed.intValue() < 0 || cpuSpeed.longValue() > Integer.MAX_VALUE)) { throw new InvalidParameterValueException("Failed to create service offering " + offeringName + ": specify the cpu speed value between 1 and " + Integer.MAX_VALUE); } if ((maxCPU <= 0 || maxCPU.longValue() > Integer.MAX_VALUE) || (minCPU <= 0 || minCPU.longValue() > Integer.MAX_VALUE ) ) { @@ -2877,16 +2340,14 @@ public ServiceOffering createServiceOffering(final CreateServiceOfferingCmd cmd) details.put(ApiConstants.MAX_CPU_NUMBER, maxCPU.toString()); } } else { - Integer maxCPUCores = VM_SERVICE_OFFERING_MAX_CPU_CORES.value() == 0 ? Integer.MAX_VALUE: VM_SERVICE_OFFERING_MAX_CPU_CORES.value(); - Integer maxRAMSize = VM_SERVICE_OFFERING_MAX_RAM_SIZE.value() == 0 ? Integer.MAX_VALUE: VM_SERVICE_OFFERING_MAX_RAM_SIZE.value(); - if (cpuNumber != null && (cpuNumber.intValue() <= 0 || cpuNumber.longValue() > maxCPUCores)) { - throw new InvalidParameterValueException("Failed to create service offering " + offeringName + ": specify the cpu number value between 1 and " + maxCPUCores); + if (cpuNumber != null && (cpuNumber.intValue() <= 0 || cpuNumber.longValue() > Integer.MAX_VALUE)) { + throw new InvalidParameterValueException("Failed to create service offering " + offeringName + ": specify the cpu number value between 1 and " + Integer.MAX_VALUE); } - if (cpuSpeed == null || (cpuSpeed.intValue() < 0 || cpuSpeed.longValue() > Integer.MAX_VALUE)) { + if (cpuSpeed != null && (cpuSpeed.intValue() < 0 || cpuSpeed.longValue() > Integer.MAX_VALUE)) { throw new InvalidParameterValueException("Failed to create service offering " + offeringName + ": specify the cpu speed value between 0 and " + Integer.MAX_VALUE); } - if (memory != null && (memory.intValue() < 32 || memory.longValue() > maxRAMSize)) { - throw new InvalidParameterValueException("Failed to create service offering " + offeringName + ": specify the memory value between 32 and " + maxRAMSize + " MB"); + if (memory != null && (memory.intValue() < 32 || memory.longValue() > Integer.MAX_VALUE)) { + throw new InvalidParameterValueException("Failed to create service offering " + offeringName + ": specify the memory value between 32 and " + Integer.MAX_VALUE + " MB"); } } @@ -2983,24 +2444,9 @@ public ServiceOffering createServiceOffering(final CreateServiceOfferingCmd cmd) } } - final Long storagePolicyId = cmd.getStoragePolicy(); - if (storagePolicyId != null) { - if (vsphereStoragePolicyDao.findById(storagePolicyId) == null) { - throw new InvalidParameterValueException("Please specify a valid vSphere storage policy id"); - } - } - - final Long diskOfferingId = cmd.getDiskOfferingId(); - if (diskOfferingId != null) { - DiskOfferingVO diskOffering = _diskOfferingDao.findById(diskOfferingId); - if ((diskOffering == null) || diskOffering.isComputeOnly()) { - throw new InvalidParameterValueException("Please specify a valid disk offering."); - } - } - return createServiceOffering(userId, cmd.isSystem(), vmType, cmd.getServiceOfferingName(), cpuNumber, memory, cpuSpeed, cmd.getDisplayText(), cmd.getProvisioningType(), localStorageRequired, offerHA, limitCpuUse, volatileVm, cmd.getTags(), cmd.getDomainIds(), cmd.getZoneIds(), cmd.getHostTag(), - cmd.getNetworkRate(), cmd.getDeploymentPlanner(), details, cmd.getRootDiskSize(), isCustomizedIops, cmd.getMinIops(), cmd.getMaxIops(), + cmd.getNetworkRate(), cmd.getDeploymentPlanner(), details, isCustomizedIops, cmd.getMinIops(), cmd.getMaxIops(), cmd.getBytesReadRate(), cmd.getBytesReadRateMax(), cmd.getBytesReadRateMaxLength(), cmd.getBytesWriteRate(), cmd.getBytesWriteRateMax(), cmd.getBytesWriteRateMaxLength(), cmd.getIopsReadRate(), cmd.getIopsReadRateMax(), cmd.getIopsReadRateMaxLength(), @@ -3029,7 +2475,7 @@ protected ServiceOfferingVO createServiceOffering(final long userId, final boole throw new InvalidParameterValueException("Unable to find active user by id " + userId); } final Account account = _accountDao.findById(user.getAccountId()); - if (account.getType() == Account.Type.DOMAIN_ADMIN) { + if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { if (filteredDomainIds.isEmpty()) { throw new InvalidParameterValueException(String.format("Unable to create public service offering by admin: %s because it is domain-admin", user.getUuid())); } @@ -3041,17 +2487,90 @@ protected ServiceOfferingVO createServiceOffering(final long userId, final boole throw new InvalidParameterValueException(String.format("Unable to create service offering by another domain-admin: %s for domain: %s", user.getUuid(), _entityMgr.findById(Domain.class, domainId).getUuid())); } } - } else if (account.getType() != Account.Type.ADMIN) { + } else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) { throw new InvalidParameterValueException(String.format("Unable to create service offering by user: %s because it is not root-admin or domain-admin", user.getUuid())); } final ProvisioningType typedProvisioningType = ProvisioningType.getProvisioningType(provisioningType); - tags = com.cloud.utils.StringUtils.cleanupTags(tags); + tags = StringUtils.cleanupTags(tags); + + ServiceOfferingVO offering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, + limitResourceUse, volatileVm, displayText, typedProvisioningType, localStorageRequired, false, tags, isSystem, vmType, + hostTag, deploymentPlanner); + + if (Boolean.TRUE.equals(isCustomizedIops) || isCustomizedIops == null) { + minIops = null; + maxIops = null; + } else { + if (minIops == null && maxIops == null) { + minIops = 0L; + maxIops = 0L; + } else { + if (minIops == null || minIops <= 0) { + throw new InvalidParameterValueException("The min IOPS must be greater than 0."); + } + + if (maxIops == null) { + maxIops = 0L; + } + + if (minIops > maxIops) { + throw new InvalidParameterValueException("The min IOPS must be less than or equal to the max IOPS."); + } + } + } + + + offering.setCustomizedIops(isCustomizedIops); + offering.setMinIops(minIops); + offering.setMaxIops(maxIops); + + if (bytesReadRate != null && bytesReadRate > 0) { + offering.setBytesReadRate(bytesReadRate); + } + if (bytesReadRateMax != null && bytesReadRateMax > 0) { + offering.setBytesReadRateMax(bytesReadRateMax); + } + if (bytesReadRateMaxLength != null && bytesReadRateMaxLength > 0) { + offering.setBytesReadRateMaxLength(bytesReadRateMaxLength); + } + if (bytesWriteRate != null && bytesWriteRate > 0) { + offering.setBytesWriteRate(bytesWriteRate); + } + if (bytesWriteRateMax != null && bytesWriteRateMax > 0) { + offering.setBytesWriteRateMax(bytesWriteRateMax); + } + if (bytesWriteRateMaxLength != null && bytesWriteRateMaxLength > 0) { + offering.setBytesWriteRateMaxLength(bytesWriteRateMaxLength); + } + if (iopsReadRate != null && iopsReadRate > 0) { + offering.setIopsReadRate(iopsReadRate); + } + if (iopsReadRateMax != null && iopsReadRateMax > 0) { + offering.setIopsReadRateMax(iopsReadRateMax); + } + if (iopsReadRateMaxLength != null && iopsReadRateMaxLength > 0) { + offering.setIopsReadRateMaxLength(iopsReadRateMaxLength); + } + if (iopsWriteRate != null && iopsWriteRate > 0) { + offering.setIopsWriteRate(iopsWriteRate); + } + if (iopsWriteRateMax != null && iopsWriteRateMax > 0) { + offering.setIopsWriteRateMax(iopsWriteRateMax); + } + if (iopsWriteRateMaxLength != null && iopsWriteRateMaxLength > 0) { + offering.setIopsWriteRateMaxLength(iopsWriteRateMaxLength); + } + if(cacheMode != null) { + offering.setCacheMode(DiskOffering.DiskCacheMode.valueOf(cacheMode.toUpperCase())); + } + + if (hypervisorSnapshotReserve != null && hypervisorSnapshotReserve < 0) { + throw new InvalidParameterValueException("If provided, Hypervisor Snapshot Reserve must be greater than or equal to 0."); + } - ServiceOfferingVO serviceOffering = new ServiceOfferingVO(name, cpu, ramSize, speed, networkRate, null, offerHA, - limitResourceUse, volatileVm, displayText, isSystem, vmType, - hostTag, deploymentPlanner, dynamicScalingEnabled, isCustomized); + offering.setHypervisorSnapshotReserve(hypervisorSnapshotReserve); List detailsVO = new ArrayList(); if (details != null) { @@ -3082,11 +2601,7 @@ protected ServiceOfferingVO createServiceOffering(final long userId, final boole continue; } } - if (detailEntry.getKey().equalsIgnoreCase(Volume.BANDWIDTH_LIMIT_IN_MBPS) || detailEntry.getKey().equalsIgnoreCase(Volume.IOPS_LIMIT)) { - // Add in disk offering details - continue; - } - detailsVO.add(new ServiceOfferingDetailsVO(serviceOffering.getId(), detailEntry.getKey(), detailEntryValue, true)); + detailsVO.add(new ServiceOfferingDetailsVO(offering.getId(), detailEntry.getKey(), detailEntryValue, true)); } } @@ -3118,23 +2633,21 @@ protected ServiceOfferingVO createServiceOffering(final long userId, final boole if ((serviceOffering = _serviceOfferingDao.persist(serviceOffering)) != null) { for (Long domainId : filteredDomainIds) { - detailsVO.add(new ServiceOfferingDetailsVO(serviceOffering.getId(), ApiConstants.DOMAIN_ID, String.valueOf(domainId), false)); + detailsVO.add(new ServiceOfferingDetailsVO(offering.getId(), ApiConstants.DOMAIN_ID, String.valueOf(domainId), false)); } if (CollectionUtils.isNotEmpty(zoneIds)) { for (Long zoneId : zoneIds) { - detailsVO.add(new ServiceOfferingDetailsVO(serviceOffering.getId(), ApiConstants.ZONE_ID, String.valueOf(zoneId), false)); + detailsVO.add(new ServiceOfferingDetailsVO(offering.getId(), ApiConstants.ZONE_ID, String.valueOf(zoneId), false)); } } - if (CollectionUtils.isNotEmpty(detailsVO)) { + if (!detailsVO.isEmpty()) { for (ServiceOfferingDetailsVO detail : detailsVO) { - detail.setResourceId(serviceOffering.getId()); + detail.setResourceId(offering.getId()); } _serviceOfferingDetailsDao.saveDetails(detailsVO); } - - CallContext.current().setEventDetails("Service offering id=" + serviceOffering.getId()); - CallContext.current().putContextParameter(ServiceOffering.class, serviceOffering.getId()); - return serviceOffering; + CallContext.current().setEventDetails("Service offering id=" + offering.getId()); + return offering; } else { return null; } @@ -3275,8 +2788,6 @@ public ServiceOffering updateServiceOffering(final UpdateServiceOfferingCmd cmd) Long userId = CallContext.current().getCallingUserId(); final List domainIds = cmd.getDomainIds(); final List zoneIds = cmd.getZoneIds(); - String storageTags = cmd.getStorageTags(); - String hostTags = cmd.getHostTags(); if (userId == null) { userId = Long.valueOf(User.UID_SYSTEM); @@ -3327,7 +2838,7 @@ public ServiceOffering updateServiceOffering(final UpdateServiceOfferingCmd cmd) } Collections.sort(filteredZoneIds); - if (account.getType() == Account.Type.DOMAIN_ADMIN) { + if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { if (!filteredZoneIds.equals(existingZoneIds)) { // Domain-admins cannot update zone(s) for offerings throw new InvalidParameterValueException(String.format("Unable to update zone(s) for service offering: %s by admin: %s as it is domain-admin", offeringHandle.getUuid(), user.getUuid())); } @@ -3354,11 +2865,11 @@ public ServiceOffering updateServiceOffering(final UpdateServiceOfferingCmd cmd) } } filteredDomainIds.addAll(nonChildDomains); // Final list must include domains which were not child domain for domain-admin but specified for this offering prior to update - } else if (account.getType() != Account.Type.ADMIN) { + } else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) { throw new InvalidParameterValueException(String.format("Unable to update service offering: %s by id user: %s because it is not root-admin or domain-admin", offeringHandle.getUuid(), user.getUuid())); } - final boolean updateNeeded = name != null || displayText != null || sortKey != null || storageTags != null || hostTags != null; + final boolean updateNeeded = name != null || displayText != null || sortKey != null; final boolean detailsUpdateNeeded = !filteredDomainIds.equals(existingDomainIds) || !filteredZoneIds.equals(existingZoneIds); if (!updateNeeded && !detailsUpdateNeeded) { return _serviceOfferingDao.findById(id); @@ -3378,11 +2889,29 @@ public ServiceOffering updateServiceOffering(final UpdateServiceOfferingCmd cmd) offering.setSortKey(sortKey); } - DiskOfferingVO diskOffering = _diskOfferingDao.findById(offeringHandle.getDiskOfferingId()); - updateOfferingTagsIfIsNotNull(storageTags, diskOffering); - _diskOfferingDao.update(diskOffering.getId(), diskOffering); - - updateServiceOfferingHostTagsIfNotNull(hostTags, offering); + // Note: tag editing commented out for now; keeping the code intact, + // might need to re-enable in next releases + // if (tags != null) + // { + // if (tags.trim().isEmpty() && offeringHandle.getTags() == null) + // { + // //no new tags; no existing tags + // offering.setTagsArray(csvTagsToList(null)); + // } + // else if (!tags.trim().isEmpty() && offeringHandle.getTags() != null) + // { + // //new tags + existing tags + // List oldTags = csvTagsToList(offeringHandle.getTags()); + // List newTags = csvTagsToList(tags); + // oldTags.addAll(newTags); + // offering.setTagsArray(oldTags); + // } + // else if(!tags.trim().isEmpty()) + // { + // //new tags; NO existing tags + // offering.setTagsArray(csvTagsToList(tags)); + // } + // } if (updateNeeded && !_serviceOfferingDao.update(id, offering)) { return null; @@ -3448,11 +2977,10 @@ protected DiskOfferingVO createDiskOffering(final Long userId, final List final Integer hypervisorSnapshotReserve, String cacheMode, final Map details, final Long storagePolicyID, final boolean diskSizeStrictness, final boolean encrypt) { long diskSize = 0;// special case for custom disk offerings - long maxVolumeSizeInGb = VolumeOrchestrationService.MaxVolumeSize.value(); if (numGibibytes != null && numGibibytes <= 0) { - throw new InvalidParameterValueException("Please specify a disk size of at least 1 GB."); - } else if (numGibibytes != null && numGibibytes > maxVolumeSizeInGb) { - throw new InvalidParameterValueException(String.format("The maximum size for a disk is %d GB.", maxVolumeSizeInGb)); + throw new InvalidParameterValueException("Please specify a disk size of at least 1 Gb."); + } else if (numGibibytes != null && numGibibytes > _maxVolumeSizeInGb) { + throw new InvalidParameterValueException("The maximum size for a disk is " + _maxVolumeSizeInGb + " Gb."); } final ProvisioningType typedProvisioningType = ProvisioningType.getProvisioningType(provisioningType); @@ -3495,7 +3023,7 @@ protected DiskOfferingVO createDiskOffering(final Long userId, final List throw new InvalidParameterValueException("Unable to find active user by id " + userId); } final Account account = _accountDao.findById(user.getAccountId()); - if (account.getType() == Account.Type.DOMAIN_ADMIN) { + if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { if (filteredDomainIds.isEmpty()) { throw new InvalidParameterValueException(String.format("Unable to create public disk offering by admin: %s because it is domain-admin", user.getUuid())); } @@ -3507,19 +3035,52 @@ protected DiskOfferingVO createDiskOffering(final Long userId, final List throw new InvalidParameterValueException(String.format("Unable to create disk offering by another domain-admin: %s for domain: %s", user.getUuid(), _entityMgr.findById(Domain.class, domainId).getUuid())); } } - } else if (account.getType() != Account.Type.ADMIN) { + } else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) { throw new InvalidParameterValueException(String.format("Unable to create disk offering by user: %s because it is not root-admin or domain-admin", user.getUuid())); } - tags = com.cloud.utils.StringUtils.cleanupTags(tags); + tags = StringUtils.cleanupTags(tags); final DiskOfferingVO newDiskOffering = new DiskOfferingVO(name, description, typedProvisioningType, diskSize, tags, isCustomized, isCustomizedIops, minIops, maxIops); newDiskOffering.setUseLocalStorage(localStorageRequired); newDiskOffering.setDisplayOffering(isDisplayOfferingEnabled); - setBytesRate(newDiskOffering, bytesReadRate, bytesReadRateMax, bytesReadRateMaxLength, bytesWriteRate, bytesWriteRateMax, bytesWriteRateMaxLength); - setIopsRate(newDiskOffering, iopsReadRate, iopsReadRateMax, iopsReadRateMaxLength, iopsWriteRate, iopsWriteRateMax, iopsWriteRateMaxLength); - + if (bytesReadRate != null && bytesReadRate > 0) { + newDiskOffering.setBytesReadRate(bytesReadRate); + } + if (bytesReadRateMax != null && bytesReadRateMax > 0) { + newDiskOffering.setBytesReadRateMax(bytesReadRateMax); + } + if (bytesReadRateMaxLength != null && bytesReadRateMaxLength > 0) { + newDiskOffering.setBytesReadRateMaxLength(bytesReadRateMaxLength); + } + if (bytesWriteRate != null && bytesWriteRate > 0) { + newDiskOffering.setBytesWriteRate(bytesWriteRate); + } + if (bytesWriteRateMax != null && bytesWriteRateMax > 0) { + newDiskOffering.setBytesWriteRateMax(bytesWriteRateMax); + } + if (bytesWriteRateMaxLength != null && bytesWriteRateMaxLength > 0) { + newDiskOffering.setBytesWriteRateMaxLength(bytesWriteRateMaxLength); + } + if (iopsReadRate != null && iopsReadRate > 0) { + newDiskOffering.setIopsReadRate(iopsReadRate); + } + if (iopsReadRateMax != null && iopsReadRateMax > 0) { + newDiskOffering.setIopsReadRateMax(iopsReadRateMax); + } + if (iopsReadRateMaxLength != null && iopsReadRateMaxLength > 0) { + newDiskOffering.setIopsReadRateMaxLength(iopsReadRateMaxLength); + } + if (iopsWriteRate != null && iopsWriteRate > 0) { + newDiskOffering.setIopsWriteRate(iopsWriteRate); + } + if (iopsWriteRateMax != null && iopsWriteRateMax > 0) { + newDiskOffering.setIopsWriteRateMax(iopsWriteRateMax); + } + if (iopsWriteRateMaxLength != null && iopsWriteRateMaxLength > 0) { + newDiskOffering.setIopsWriteRateMaxLength(iopsWriteRateMaxLength); + } if (cacheMode != null) { newDiskOffering.setCacheMode(DiskOffering.DiskCacheMode.valueOf(cacheMode.toUpperCase())); } @@ -3530,7 +3091,6 @@ protected DiskOfferingVO createDiskOffering(final Long userId, final List newDiskOffering.setEncrypt(encrypt); newDiskOffering.setHypervisorSnapshotReserve(hypervisorSnapshotReserve); - newDiskOffering.setDiskSizeStrictness(diskSizeStrictness); CallContext.current().setEventDetails("Disk offering id=" + newDiskOffering.getId()); final DiskOfferingVO offering = _diskOfferingDao.persist(newDiskOffering); @@ -3558,7 +3118,6 @@ protected DiskOfferingVO createDiskOffering(final Long userId, final List diskOfferingDetailsDao.saveDetails(detailsVO); } CallContext.current().setEventDetails("Disk offering id=" + newDiskOffering.getId()); - CallContext.current().putContextParameter(DiskOffering.class, newDiskOffering.getId()); return offering; } return null; @@ -3576,9 +3135,6 @@ public DiskOffering createDiskOffering(final CreateDiskOfferingCmd cmd) { final String tags = cmd.getTags(); final List domainIds = cmd.getDomainIds(); final List zoneIds = cmd.getZoneIds(); - final Map details = cmd.getDetails(); - final Long storagePolicyId = cmd.getStoragePolicy(); - final boolean diskSizeStrictness = cmd.getDiskSizeStrictness(); // check if valid domain if (CollectionUtils.isNotEmpty(domainIds)) { @@ -3618,12 +3174,6 @@ public DiskOffering createDiskOffering(final CreateDiskOfferingCmd cmd) { } } - if (storagePolicyId != null) { - if (vsphereStoragePolicyDao.findById(storagePolicyId) == null) { - throw new InvalidParameterValueException("Please specify a valid vSphere storage policy id"); - } - } - final Boolean isCustomizedIops = cmd.isCustomizedIops(); final Long minIops = cmd.getMinIops(); final Long maxIops = cmd.getMaxIops(); @@ -3719,21 +3269,6 @@ public DiskOffering updateDiskOffering(final UpdateDiskOfferingCmd cmd) { final Boolean displayDiskOffering = cmd.getDisplayOffering(); final List domainIds = cmd.getDomainIds(); final List zoneIds = cmd.getZoneIds(); - final String tags = cmd.getTags(); - - Long bytesReadRate = cmd.getBytesReadRate(); - Long bytesReadRateMax = cmd.getBytesReadRateMax(); - Long bytesReadRateMaxLength = cmd.getBytesReadRateMaxLength(); - Long bytesWriteRate = cmd.getBytesWriteRate(); - Long bytesWriteRateMax = cmd.getBytesWriteRateMax(); - Long bytesWriteRateMaxLength = cmd.getBytesWriteRateMaxLength(); - Long iopsReadRate = cmd.getIopsReadRate(); - Long iopsReadRateMax = cmd.getIopsReadRateMax(); - Long iopsReadRateMaxLength = cmd.getIopsReadRateMaxLength(); - Long iopsWriteRate = cmd.getIopsWriteRate(); - Long iopsWriteRateMax = cmd.getIopsWriteRateMax(); - Long iopsWriteRateMaxLength = cmd.getIopsWriteRateMaxLength(); - String cacheMode = cmd.getCacheMode(); // Check if diskOffering exists final DiskOffering diskOfferingHandle = _entityMgr.findById(DiskOffering.class, diskOfferingId); @@ -3784,7 +3319,7 @@ public DiskOffering updateDiskOffering(final UpdateDiskOfferingCmd cmd) { } Collections.sort(filteredZoneIds); - if (account.getType() == Account.Type.DOMAIN_ADMIN) { + if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { if (!filteredZoneIds.equals(existingZoneIds)) { // Domain-admins cannot update zone(s) for offerings throw new InvalidParameterValueException(String.format("Unable to update zone(s) for disk offering: %s by admin: %s as it is domain-admin", diskOfferingHandle.getUuid(), user.getUuid())); } @@ -3811,14 +3346,11 @@ public DiskOffering updateDiskOffering(final UpdateDiskOfferingCmd cmd) { } } filteredDomainIds.addAll(nonChildDomains); // Final list must include domains which were not child domain for domain-admin but specified for this offering prior to update - } else if (account.getType() != Account.Type.ADMIN) { + } else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) { throw new InvalidParameterValueException(String.format("Unable to update disk offering: %s by id user: %s because it is not root-admin or domain-admin", diskOfferingHandle.getUuid(), user.getUuid())); } - boolean updateNeeded = shouldUpdateDiskOffering(name, displayText, sortKey, displayDiskOffering, tags, cacheMode) || - shouldUpdateIopsRateParameters(iopsReadRate, iopsReadRateMax, iopsReadRateMaxLength, iopsWriteRate, iopsWriteRateMax, iopsWriteRateMaxLength) || - shouldUpdateBytesRateParameters(bytesReadRate, bytesReadRateMax, bytesReadRateMaxLength, bytesWriteRate, bytesWriteRateMax, bytesWriteRateMaxLength); - + final boolean updateNeeded = name != null || displayText != null || sortKey != null || displayDiskOffering != null; final boolean detailsUpdateNeeded = !filteredDomainIds.equals(existingDomainIds) || !filteredZoneIds.equals(existingZoneIds); if (!updateNeeded && !detailsUpdateNeeded) { return _diskOfferingDao.findById(diskOfferingId); @@ -3842,21 +3374,30 @@ public DiskOffering updateDiskOffering(final UpdateDiskOfferingCmd cmd) { diskOffering.setDisplayOffering(displayDiskOffering); } - updateOfferingTagsIfIsNotNull(tags, diskOffering); - - validateMaxRateEqualsOrGreater(iopsReadRate, iopsReadRateMax, IOPS_READ_RATE); - validateMaxRateEqualsOrGreater(iopsWriteRate, iopsWriteRateMax, IOPS_WRITE_RATE); - validateMaxRateEqualsOrGreater(bytesReadRate, bytesReadRateMax, BYTES_READ_RATE); - validateMaxRateEqualsOrGreater(bytesWriteRate, bytesWriteRateMax, BYTES_WRITE_RATE); - validateMaximumIopsAndBytesLength(iopsReadRateMaxLength, iopsWriteRateMaxLength, bytesReadRateMaxLength, bytesWriteRateMaxLength); - - setBytesRate(diskOffering, bytesReadRate, bytesReadRateMax, bytesReadRateMaxLength, bytesWriteRate, bytesWriteRateMax, bytesWriteRateMaxLength); - setIopsRate(diskOffering, iopsReadRate, iopsReadRateMax, iopsReadRateMaxLength, iopsWriteRate, iopsWriteRateMax, iopsWriteRateMaxLength); - - if (cacheMode != null) { - validateCacheMode(cacheMode); - diskOffering.setCacheMode(DiskOffering.DiskCacheMode.valueOf(cacheMode.toUpperCase())); - } + // Note: tag editing commented out for now;keeping the code intact, + // might need to re-enable in next releases + // if (tags != null) + // { + // if (tags.trim().isEmpty() && diskOfferingHandle.getTags() == null) + // { + // //no new tags; no existing tags + // diskOffering.setTagsArray(csvTagsToList(null)); + // } + // else if (!tags.trim().isEmpty() && diskOfferingHandle.getTags() != + // null) + // { + // //new tags + existing tags + // List oldTags = csvTagsToList(diskOfferingHandle.getTags()); + // List newTags = csvTagsToList(tags); + // oldTags.addAll(newTags); + // diskOffering.setTagsArray(oldTags); + // } + // else if(!tags.trim().isEmpty()) + // { + // //new tags; NO existing tags + // diskOffering.setTagsArray(csvTagsToList(tags)); + // } + // } if (updateNeeded && !_diskOfferingDao.update(diskOfferingId, diskOffering)) { return null; @@ -3875,104 +3416,22 @@ public DiskOffering updateDiskOffering(final UpdateDiskOfferingCmd cmd) { for (Long domainId : filteredDomainIds) { detailsVO.add(new DiskOfferingDetailVO(diskOfferingId, ApiConstants.DOMAIN_ID, String.valueOf(domainId), false)); } - } - if(!filteredZoneIds.equals(existingZoneIds)) { - sc.setParameters("detailName", ApiConstants.ZONE_ID); - diskOfferingDetailsDao.remove(sc); - for (Long zoneId : filteredZoneIds) { - detailsVO.add(new DiskOfferingDetailVO(diskOfferingId, ApiConstants.ZONE_ID, String.valueOf(zoneId), false)); - } - } - } - if (!detailsVO.isEmpty()) { - for (DiskOfferingDetailVO detailVO : detailsVO) { - diskOfferingDetailsDao.persist(detailVO); - } - } - CallContext.current().setEventDetails("Disk offering id=" + diskOffering.getId()); - return _diskOfferingDao.findById(diskOfferingId); - } - - /** - * Check the tags parameters to the disk/service offering - *
    - *
  • If tags is null, do nothing and return.
  • - *
  • If tags is not null, will set tag to the disk/service offering if the pools with active volumes have the new tags.
  • - *
  • If tags is an blank string, set null on disk/service offering tag.
  • - *
- */ - protected void updateOfferingTagsIfIsNotNull(String tags, DiskOfferingVO diskOffering) { - if (tags == null) { return; } - if (StringUtils.isNotBlank(tags)) { - tags = com.cloud.utils.StringUtils.cleanupTags(tags); - List pools = _storagePoolDao.listStoragePoolsWithActiveVolumesByOfferingId(diskOffering.getId()); - if (CollectionUtils.isNotEmpty(pools)) { - List listOfTags = Arrays.asList(tags.split(",")); - for (StoragePoolVO storagePoolVO : pools) { - List tagsOnPool = storagePoolTagDao.getStoragePoolTags(storagePoolVO.getId()); - if (CollectionUtils.isEmpty(tagsOnPool) || !tagsOnPool.containsAll(listOfTags)) { - DiskOfferingVO offeringToRetrieveInfo = _diskOfferingDao.findById(diskOffering.getId()); - List volumes = _volumeDao.findByDiskOfferingId(diskOffering.getId()); - String listOfVolumesNamesAndUuid = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(volumes, "name", "uuid"); - String diskOfferingInfo = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(offeringToRetrieveInfo, "name", "uuid"); - String poolInfo = ReflectionToStringBuilderUtils.reflectOnlySelectedFields(storagePoolVO, "name", "uuid"); - throw new InvalidParameterValueException(String.format("There are active volumes using the disk offering %s, and the pool %s doesn't have the new tags. " + - "The following volumes are using the mentioned disk offering %s. Please first add the new tags to the mentioned storage pools before adding them" + - " to the disk offering.", diskOfferingInfo, poolInfo, listOfVolumesNamesAndUuid)); - } + } + if(!filteredZoneIds.equals(existingZoneIds)) { + sc.setParameters("detailName", ApiConstants.ZONE_ID); + diskOfferingDetailsDao.remove(sc); + for (Long zoneId : filteredZoneIds) { + detailsVO.add(new DiskOfferingDetailVO(diskOfferingId, ApiConstants.ZONE_ID, String.valueOf(zoneId), false)); } } - diskOffering.setTags(tags); - } else { - diskOffering.setTags(null); - } - } - - /** - * Check the host tags parameters to the service offering - *
    - *
  • If host tags is null, do nothing and return.
  • - *
  • If host tags is not null, will set host tag to the service offering if the hosts with active VMs have the new tags.
  • - *
  • If host tags is an blank string, set null on service offering tag.
  • - *
- */ - protected void updateServiceOfferingHostTagsIfNotNull(String hostTags, ServiceOfferingVO offering) { - if (hostTags == null) { - return; } - if (StringUtils.isNotBlank(hostTags)) { - hostTags = com.cloud.utils.StringUtils.cleanupTags(hostTags); - List hosts = _hostDao.listHostsWithActiveVMs(offering.getId()); - if (CollectionUtils.isNotEmpty(hosts)) { - List listOfHostTags = Arrays.asList(hostTags.split(",")); - for (HostVO host : hosts) { - List tagsOnHost = hostTagDao.getHostTags(host.getId()); - if (CollectionUtils.isEmpty(tagsOnHost) || !tagsOnHost.containsAll(listOfHostTags)) { - throw new InvalidParameterValueException(String.format("There are active VMs using offering [%s], and the hosts [%s] don't have the new tags", offering.getId(), hosts)); - } - } + if (!detailsVO.isEmpty()) { + for (DiskOfferingDetailVO detailVO : detailsVO) { + diskOfferingDetailsDao.persist(detailVO); } - offering.setHostTag(hostTags); - } else { - offering.setHostTag(null); } - } - - /** - * Check if it needs to update any parameter when updateDiskoffering is called - * Verify if name or displayText are not blank, tags is not null, sortkey and displayDiskOffering is not null - */ - protected boolean shouldUpdateDiskOffering(String name, String displayText, Integer sortKey, Boolean displayDiskOffering, String tags, String cacheMode) { - return !StringUtils.isAllBlank(name, displayText, cacheMode) || tags != null || sortKey != null || displayDiskOffering != null; - } - - protected boolean shouldUpdateBytesRateParameters(Long bytesReadRate, Long bytesReadRateMax, Long bytesReadRateMaxLength, Long bytesWriteRate, Long bytesWriteRateMax, Long bytesWriteRateMaxLength) { - return bytesReadRate != null || bytesReadRateMax != null || bytesReadRateMaxLength != null || bytesWriteRate != null || - bytesWriteRateMax != null || bytesWriteRateMaxLength != null; - } - - protected boolean shouldUpdateIopsRateParameters(Long iopsReadRate, Long iopsReadRateMax, Long iopsReadRateMaxLength, Long iopsWriteRate, Long iopsWriteRateMax, Long iopsWriteRateMaxLength) { - return iopsReadRate != null || iopsReadRateMax != null || iopsReadRateMaxLength != null || iopsWriteRate != null || iopsWriteRateMax != null || iopsWriteRateMaxLength != null; + CallContext.current().setEventDetails("Disk offering id=" + diskOffering.getId()); + return _diskOfferingDao.findById(diskOfferingId); } @Override @@ -3995,7 +3454,7 @@ public boolean deleteDiskOffering(final DeleteDiskOfferingCmd cmd) { throw new InvalidParameterValueException("Unable to find active user by id " + userId); } final Account account = _accountDao.findById(user.getAccountId()); - if (account.getType() == Account.Type.DOMAIN_ADMIN) { + if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { List existingDomainIds = diskOfferingDetailsDao.findDomainIds(diskOfferingId); if (existingDomainIds.isEmpty()) { throw new InvalidParameterValueException(String.format("Unable to delete public disk offering: %s by admin: %s because it is domain-admin", offering.getUuid(), user.getUuid())); @@ -4005,11 +3464,10 @@ public boolean deleteDiskOffering(final DeleteDiskOfferingCmd cmd) { throw new InvalidParameterValueException(String.format("Unable to delete disk offering: %s as it has linked domain(s) which are not child domain for domain-admin: %s", offering.getUuid(), user.getUuid())); } } - } else if (account.getType() != Account.Type.ADMIN) { + } else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) { throw new InvalidParameterValueException(String.format("Unable to delete disk offering: %s by user: %s because it is not root-admin or domain-admin", offering.getUuid(), user.getUuid())); } - annotationDao.removeByEntityType(AnnotationService.EntityType.DISK_OFFERING.name(), offering.getUuid()); offering.setState(DiskOffering.State.Inactive); if (_diskOfferingDao.update(offering.getId(), offering)) { CallContext.current().setEventDetails("Disk offering id=" + diskOfferingId); @@ -4054,12 +3512,6 @@ public boolean deleteServiceOffering(final DeleteServiceOfferingCmd cmd) { throw new InvalidParameterValueException("unable to find service offering " + offeringId); } - // Verify disk offering id mapped to the service offering - final DiskOfferingVO diskOffering = _diskOfferingDao.findById(offering.getDiskOfferingId()); - if (diskOffering == null) { - throw new InvalidParameterValueException("unable to find disk offering " + offering.getDiskOfferingId() + " mapped to the service offering " + offeringId); - } - if (offering.getDefaultUse()) { throw new InvalidParameterValueException("Default service offerings cannot be deleted"); } @@ -4069,7 +3521,7 @@ public boolean deleteServiceOffering(final DeleteServiceOfferingCmd cmd) { throw new InvalidParameterValueException("Unable to find active user by id " + userId); } final Account account = _accountDao.findById(user.getAccountId()); - if (account.getType() == Account.Type.DOMAIN_ADMIN) { + if (account.getType() == Account.ACCOUNT_TYPE_DOMAIN_ADMIN) { List existingDomainIds = _serviceOfferingDetailsDao.findDomainIds(offeringId); if (existingDomainIds.isEmpty()) { throw new InvalidParameterValueException(String.format("Unable to delete public service offering: %s by admin: %s because it is domain-admin", offering.getUuid(), user.getUuid())); @@ -4079,18 +3531,11 @@ public boolean deleteServiceOffering(final DeleteServiceOfferingCmd cmd) { throw new InvalidParameterValueException(String.format("Unable to delete service offering: %s as it has linked domain(s) which are not child domain for domain-admin: %s", offering.getUuid(), user.getUuid())); } } - } else if (account.getType() != Account.Type.ADMIN) { + } else if (account.getType() != Account.ACCOUNT_TYPE_ADMIN) { throw new InvalidParameterValueException(String.format("Unable to delete service offering: %s by user: %s because it is not root-admin or domain-admin", offering.getUuid(), user.getUuid())); } - annotationDao.removeByEntityType(AnnotationService.EntityType.SERVICE_OFFERING.name(), offering.getUuid()); - if (diskOffering.isComputeOnly()) { - diskOffering.setState(DiskOffering.State.Inactive); - if (!_diskOfferingDao.update(diskOffering.getId(), diskOffering)) { - throw new CloudRuntimeException(String.format("Unable to delete disk offering %s mapped to the service offering %s", diskOffering.getUuid(), offering.getUuid())); - } - } - offering.setState(ServiceOffering.State.Inactive); + offering.setState(DiskOffering.State.Inactive); if (_serviceOfferingDao.update(offeringId, offering)) { CallContext.current().setEventDetails("Service offering id=" + offeringId); return true; @@ -4103,7 +3548,7 @@ public boolean deleteServiceOffering(final DeleteServiceOfferingCmd cmd) { @DB @ActionEvent(eventType = EventTypes.EVENT_VLAN_IP_RANGE_CREATE, eventDescription = "creating vlan ip range", async = false) public Vlan createVlanAndPublicIpRange(final CreateVlanIpRangeCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, - ResourceAllocationException { + ResourceAllocationException { Long zoneId = cmd.getZoneId(); final Long podId = cmd.getPodId(); final String startIP = cmd.getStartIp(); @@ -4134,10 +3579,10 @@ public Vlan createVlanAndPublicIpRange(final CreateVlanIpRangeCmd cmd) throws In } final boolean ipv4 = startIP != null; - final boolean ipv6 = ip6Cidr != null; + final boolean ipv6 = startIPv6 != null; if (!ipv4 && !ipv6) { - throw new InvalidParameterValueException("StartIP or IPv6 CIDR is missing in the parameters!"); + throw new InvalidParameterValueException("StartIP or StartIPv6 is missing in the parameters!"); } if (ipv4) { @@ -4152,11 +3597,6 @@ public Vlan createVlanAndPublicIpRange(final CreateVlanIpRangeCmd cmd) throws In if (endIPv6 == null && startIPv6 != null) { endIPv6 = startIPv6; } - - IPv6Network iPv6Network = IPv6Network.fromString(ip6Cidr); - if (iPv6Network.getNetmask().asPrefixLength() > Ipv6Service.IPV6_SLAAC_CIDR_NETMASK) { - throw new InvalidParameterValueException(String.format("For IPv6 range, prefix must be /%d or less", Ipv6Service.IPV6_SLAAC_CIDR_NETMASK)); - } } if (projectId != null) { @@ -4200,6 +3640,8 @@ public Vlan createVlanAndPublicIpRange(final CreateVlanIpRangeCmd cmd) throws In zoneId = network.getDataCenterId(); physicalNetworkId = network.getPhysicalNetworkId(); } + } else if (ipv6) { + throw new InvalidParameterValueException("Only support IPv6 on extending existed network"); } // Verify that zone exists @@ -4208,6 +3650,11 @@ public Vlan createVlanAndPublicIpRange(final CreateVlanIpRangeCmd cmd) throws In throw new InvalidParameterValueException("Unable to find zone by id " + zoneId); } + if (ipv6) { + if (network.getGuestType() != GuestType.Shared || zone.isSecurityGroupEnabled()) { + throw new InvalidParameterValueException("Only support IPv6 on extending existed share network without SG"); + } + } // verify that physical network exists PhysicalNetworkVO pNtwk = null; if (physicalNetworkId != null) { @@ -4281,7 +3728,7 @@ public Vlan createVlanAndPublicIpRange(final CreateVlanIpRangeCmd cmd) throws In } } else if (network.getGuestType() == null || network.getGuestType() == Network.GuestType.Isolated - && _ntwkOffServiceMapDao.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Service.SourceNat)) { + && _ntwkOffServiceMapDao.areServicesSupportedByNetworkOffering(network.getNetworkOfferingId(), Service.SourceNat)) { throw new InvalidParameterValueException("Can't create direct vlan for network id=" + networkId + " with type: " + network.getGuestType()); } } @@ -4343,8 +3790,8 @@ public Vlan createVlanAndPublicIpRange(final CreateVlanIpRangeCmd cmd) throws In } private Vlan commitVlan(final Long zoneId, final Long podId, final String startIP, final String endIP, final String newVlanGatewayFinal, final String newVlanNetmaskFinal, - final String vlanId, final Boolean forVirtualNetwork, final Boolean forSystemVms, final Long networkId, final Long physicalNetworkId, final String startIPv6, final String endIPv6, - final String ip6Gateway, final String ip6Cidr, final Domain domain, final Account vlanOwner, final Network network, final Pair> sameSubnet) { + final String vlanId, final Boolean forVirtualNetwork, final Boolean forSystemVms, final Long networkId, final Long physicalNetworkId, final String startIPv6, final String endIPv6, + final String ip6Gateway, final String ip6Cidr, final Domain domain, final Account vlanOwner, final Network network, final Pair> sameSubnet) { final GlobalLock commitVlanLock = GlobalLock.getInternLock("CommitVlan"); commitVlanLock.lock(5); s_logger.debug("Acquiring lock for committing vlan"); @@ -4358,7 +3805,7 @@ public Vlan doInTransaction(final TransactionStatus status) { if ((sameSubnet == null || !sameSubnet.first()) && network.getTrafficType() == TrafficType.Guest && network.getGuestType() == GuestType.Shared && _vlanDao.listVlansByNetworkId(networkId) != null) { final Map dhcpCapabilities = _networkSvc.getNetworkOfferingServiceCapabilities(_networkOfferingDao.findById(network.getNetworkOfferingId()), - Service.Dhcp); + Service.Dhcp); final String supportsMultipleSubnets = dhcpCapabilities.get(Capability.DhcpAccrossMultipleSubnets); if (supportsMultipleSubnets == null || !Boolean.valueOf(supportsMultipleSubnets)) { throw new InvalidParameterValueException("The dhcp service provider for this network does not support dhcp across multiple subnets"); @@ -4387,7 +3834,7 @@ public NetUtils.SupersetOrSubset checkIfSubsetOrSuperset(String vlanGateway, Str if (newVlanGateway == null && newVlanNetmask == null) { newVlanGateway = vlanGateway; newVlanNetmask = vlanNetmask; - // this means we are trying to add to the existing subnet. + // this means he is trying to add to the existing subnet. if (NetUtils.sameSubnet(newStartIP, newVlanGateway, newVlanNetmask)) { if (NetUtils.sameSubnet(newEndIP, newVlanGateway, newVlanNetmask)) { return NetUtils.SupersetOrSubset.sameSubnet; @@ -4412,7 +3859,7 @@ public NetUtils.SupersetOrSubset checkIfSubsetOrSuperset(String vlanGateway, Str } public Pair> validateIpRange(final String startIP, final String endIP, final String newVlanGateway, final String newVlanNetmask, final List vlans, final boolean ipv4, - final boolean ipv6, String ip6Gateway, String ip6Cidr, final String startIPv6, final String endIPv6, final Network network) { + final boolean ipv6, String ip6Gateway, String ip6Cidr, final String startIPv6, final String endIPv6, final Network network) { String vlanGateway = null; String vlanNetmask = null; boolean sameSubnet = false; @@ -4449,7 +3896,7 @@ public Pair> validateIpRange(final String startIP, } public boolean hasSameSubnet(boolean ipv4, String vlanGateway, String vlanNetmask, String newVlanGateway, String newVlanNetmask, String newStartIp, String newEndIp, - boolean ipv6, String newIp6Gateway, String newIp6Cidr, String newIp6StartIp, String newIp6EndIp, Network network) { + boolean ipv6, String newIp6Gateway, String newIp6Cidr, String newIp6StartIp, String newIp6EndIp, Network network) { if (ipv4) { // check if subset or super set or neither. final NetUtils.SupersetOrSubset val = checkIfSubsetOrSuperset(vlanGateway, vlanNetmask, newVlanGateway, newVlanNetmask, newStartIp, newEndIp); @@ -4462,7 +3909,7 @@ public boolean hasSameSubnet(boolean ipv4, String vlanGateway, String vlanNetmas // this implies the user is trying to add a new subnet // which is not a superset or subset of this subnet. } else if (val == NetUtils.SupersetOrSubset.isSubset) { - // this means we are trying to add to the same subnet. + // this means he is trying to add to the same subnet. throw new InvalidParameterValueException("The subnet you are trying to add is a subset of the existing subnet having gateway " + vlanGateway + " and netmask " + vlanNetmask); } else if (val == NetUtils.SupersetOrSubset.sameSubnet) { @@ -4492,7 +3939,7 @@ public boolean hasSameSubnet(boolean ipv4, String vlanGateway, String vlanNetmas @Override @DB public Vlan createVlanAndPublicIpRange(final long zoneId, final long networkId, final long physicalNetworkId, final boolean forVirtualNetwork, final boolean forSystemVms, final Long podId, final String startIP, final String endIP, - final String vlanGateway, final String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, final Account vlanOwner, final String startIPv6, final String endIPv6, final String vlanIp6Gateway, final String vlanIp6Cidr) { + final String vlanGateway, final String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, final Account vlanOwner, final String startIPv6, final String endIPv6, final String vlanIp6Gateway, final String vlanIp6Cidr) { final Network network = _networkModel.getNetwork(networkId); boolean ipv4 = false, ipv6 = false; @@ -4501,7 +3948,7 @@ public Vlan createVlanAndPublicIpRange(final long zoneId, final long networkId, ipv4 = true; } - if (vlanIp6Cidr != null) { + if (startIPv6 != null) { ipv6 = true; } @@ -4555,14 +4002,14 @@ public Vlan createVlanAndPublicIpRange(final long zoneId, final long networkId, networkVlanId = network.getBroadcastDomainType().toUri(network.getUuid()).toString(); } else if (uri != null) { // Do not search for the VLAN tag when the network doesn't support VLAN - if (uri.toString().startsWith("vlan")) { + if (uri.toString().startsWith("vlan")) { final String[] vlan = uri.toString().split("vlan:\\/\\/"); networkVlanId = vlan[1]; // For pvlan if (network.getBroadcastDomainType() != BroadcastDomainType.Vlan) { networkVlanId = networkVlanId.split("-")[0]; } - } + } } if (vlanId != null && !connectivityWithoutVlan) { @@ -4609,7 +4056,6 @@ public Vlan createVlanAndPublicIpRange(final long zoneId, final long networkId, } } - boolean isSharedNetworkWithoutSpecifyVlan = _networkMgr.isSharedNetworkWithoutSpecifyVlan(_networkOfferingDao.findById(network.getNetworkOfferingId())); if (ipv4) { final String newCidr = NetUtils.getCidrFromGatewayAndNetmask(vlanGateway, vlanNetmask); @@ -4634,15 +4080,76 @@ public Vlan createVlanAndPublicIpRange(final long zoneId, final long networkId, checkConflictsWithPortableIpRange(zoneId, vlanId, vlanGateway, vlanNetmask, startIP, endIP); - if (!isSharedNetworkWithoutSpecifyVlan) { - checkZoneVlanIpOverlap(zone, network, newCidr, vlanId, vlanGateway, vlanNetmask, startIP, endIP); + // Throw an exception if this subnet overlaps with subnet on other VLAN, + // if this is ip range extension, gateway, network mask should be same and ip range should not overlap + + final List vlans = _vlanDao.listByZone(zone.getId()); + for (final VlanVO vlan : vlans) { + final String otherVlanGateway = vlan.getVlanGateway(); + final String otherVlanNetmask = vlan.getVlanNetmask(); + // Continue if it's not IPv4 + if ( otherVlanGateway == null || otherVlanNetmask == null ) { + continue; + } + if ( vlan.getNetworkId() == null ) { + continue; + } + final String otherCidr = NetUtils.getCidrFromGatewayAndNetmask(otherVlanGateway, otherVlanNetmask); + if( !NetUtils.isNetworksOverlap(newCidr, otherCidr)) { + continue; + } + // from here, subnet overlaps + if (vlanId.toLowerCase().contains(Vlan.UNTAGGED) || UriUtils.checkVlanUriOverlap( + BroadcastDomainType.getValue(BroadcastDomainType.fromString(vlanId)), + BroadcastDomainType.getValue(BroadcastDomainType.fromString(vlan.getVlanTag())))) { + // For untagged VLAN Id and overlapping URIs we need to expand and verify IP ranges + final String[] otherVlanIpRange = vlan.getIpRange().split("\\-"); + final String otherVlanStartIP = otherVlanIpRange[0]; + String otherVlanEndIP = null; + if (otherVlanIpRange.length > 1) { + otherVlanEndIP = otherVlanIpRange[1]; + } + + // extend IP range + if (!vlanGateway.equals(otherVlanGateway) || !vlanNetmask.equals(vlan.getVlanNetmask())) { + throw new InvalidParameterValueException("The IP range has already been added with gateway " + + otherVlanGateway + " ,and netmask " + otherVlanNetmask + + ", Please specify the gateway/netmask if you want to extend ip range" ); + } + if (!NetUtils.is31PrefixCidr(newCidr)) { + if (NetUtils.ipRangesOverlap(startIP, endIP, otherVlanStartIP, otherVlanEndIP)) { + throw new InvalidParameterValueException("The IP range already has IPs that overlap with the new range." + + " Please specify a different start IP/end IP."); + } + } + } else { + // For tagged or non-overlapping URIs we need to ensure there is no Public traffic type + boolean overlapped = false; + if (network.getTrafficType() == TrafficType.Public) { + overlapped = true; + } else { + final Long nwId = vlan.getNetworkId(); + if (nwId != null) { + final Network nw = _networkModel.getNetwork(nwId); + if (nw != null && nw.getTrafficType() == TrafficType.Public) { + overlapped = true; + } + } + + } + if (overlapped) { + throw new InvalidParameterValueException("The IP range with tag: " + vlan.getVlanTag() + + " in zone " + zone.getName() + + " has overlapped with the subnet. Please specify a different gateway/netmask."); + } + } } } String ipv6Range = null; if (ipv6) { ipv6Range = startIPv6; - if (StringUtils.isNotEmpty(ipv6Range) && StringUtils.isNotEmpty(endIPv6)) { + if (endIPv6 != null) { ipv6Range += "-" + endIPv6; } @@ -4651,30 +4158,21 @@ public Vlan createVlanAndPublicIpRange(final long zoneId, final long networkId, if (vlan.getIp6Gateway() == null) { continue; } - if ((StringUtils.isAllEmpty(ipv6Range, vlan.getIp6Range())) && - NetUtils.ipv6NetworksOverlap(IPv6Network.fromString(vlanIp6Cidr), IPv6Network.fromString(vlan.getIp6Cidr()))) { - throw new InvalidParameterValueException(String.format("The IPv6 range with tag: %s already has IPs that overlap with the new range.", - vlan.getVlanTag())); - } - if (!StringUtils.isAllEmpty(ipv6Range, vlan.getIp6Range())) { - String r1 = StringUtils.isEmpty(ipv6Range) ? NetUtils.getIpv6RangeFromCidr(vlanIp6Cidr) : ipv6Range; - String r2 = StringUtils.isEmpty(vlan.getIp6Range()) ? NetUtils.getIpv6RangeFromCidr(vlan.getIp6Cidr()) : vlan.getIp6Range(); - if(NetUtils.isIp6RangeOverlap(r1, r2)) { - throw new InvalidParameterValueException(String.format("The IPv6 range with tag: %s already has IPs that overlap with the new range.", - vlan.getVlanTag())); + if (NetUtils.isSameIsolationId(vlanId, vlan.getVlanTag())) { + if (NetUtils.isIp6RangeOverlap(ipv6Range, vlan.getIp6Range())) { + throw new InvalidParameterValueException("The IPv6 range with tag: " + vlan.getVlanTag() + + " already has IPs that overlap with the new range. Please specify a different start IP/end IP."); + } + + if (!vlanIp6Gateway.equals(vlan.getIp6Gateway())) { + throw new InvalidParameterValueException("The IP range with tag: " + vlan.getVlanTag() + " has already been added with gateway " + vlan.getIp6Gateway() + + ". Please specify a different tag."); } - } - if (NetUtils.isSameIsolationId(vlanId, vlan.getVlanTag()) && !vlanIp6Gateway.equals(vlan.getIp6Gateway())) { - throw new InvalidParameterValueException(String.format("The IP range with tag: %s has already been added with gateway %s. Please specify a different tag.", - vlan.getVlanTag(), vlan.getIp6Gateway())); } } } // Check if the vlan is being used - if (isSharedNetworkWithoutSpecifyVlan) { - bypassVlanOverlapCheck = true; - } if (!bypassVlanOverlapCheck && _zoneDao.findVnet(zoneId, physicalNetworkId, BroadcastDomainType.getValue(BroadcastDomainType.fromString(vlanId))).size() > 0) { throw new InvalidParameterValueException("The VLAN tag " + vlanId + " is already being used for dynamic vlan allocation for the guest network in zone " + zone.getName()); @@ -4696,71 +4194,9 @@ public Vlan createVlanAndPublicIpRange(final long zoneId, final long networkId, return vlan; } - private void checkZoneVlanIpOverlap(DataCenterVO zone, Network network, String newCidr, String vlanId, String vlanGateway, String vlanNetmask, String startIP, String endIP) { - // Throw an exception if this subnet overlaps with subnet on other VLAN, - // if this is ip range extension, gateway, network mask should be same and ip range should not overlap - - final List vlans = _vlanDao.listByZone(zone.getId()); - for (final VlanVO vlan : vlans) { - final String otherVlanGateway = vlan.getVlanGateway(); - final String otherVlanNetmask = vlan.getVlanNetmask(); - // Continue if it's not IPv4 - if (ObjectUtils.anyNull(otherVlanGateway, otherVlanNetmask, vlan.getNetworkId())) { - continue; - } - final String otherCidr = NetUtils.getCidrFromGatewayAndNetmask(otherVlanGateway, otherVlanNetmask); - if( !NetUtils.isNetworksOverlap(newCidr, otherCidr)) { - continue; - } - // from here, subnet overlaps - if (vlanId.toLowerCase().contains(Vlan.UNTAGGED) || UriUtils.checkVlanUriOverlap( - BroadcastDomainType.getValue(BroadcastDomainType.fromString(vlanId)), - BroadcastDomainType.getValue(BroadcastDomainType.fromString(vlan.getVlanTag())))) { - // For untagged VLAN Id and overlapping URIs we need to expand and verify IP ranges - final String[] otherVlanIpRange = vlan.getIpRange().split("\\-"); - final String otherVlanStartIP = otherVlanIpRange[0]; - String otherVlanEndIP = null; - if (otherVlanIpRange.length > 1) { - otherVlanEndIP = otherVlanIpRange[1]; - } - - // extend IP range - if (!vlanGateway.equals(otherVlanGateway) || !vlanNetmask.equals(vlan.getVlanNetmask())) { - throw new InvalidParameterValueException("The IP range has already been added with gateway " - + otherVlanGateway + " ,and netmask " + otherVlanNetmask - + ", Please specify the gateway/netmask if you want to extend ip range" ); - } - if (!NetUtils.is31PrefixCidr(newCidr) && NetUtils.ipRangesOverlap(startIP, endIP, otherVlanStartIP, otherVlanEndIP)) { - throw new InvalidParameterValueException("The IP range already has IPs that overlap with the new range." + - " Please specify a different start IP/end IP."); - } - } else { - // For tagged or non-overlapping URIs we need to ensure there is no Public traffic type - boolean overlapped = false; - if (network.getTrafficType() == TrafficType.Public) { - overlapped = true; - } else { - final Long nwId = vlan.getNetworkId(); - if (nwId != null) { - final Network nw = _networkModel.getNetwork(nwId); - if (nw != null && nw.getTrafficType() == TrafficType.Public) { - overlapped = true; - } - } - - } - if (overlapped) { - throw new InvalidParameterValueException("The IP range with tag: " + vlan.getVlanTag() - + " in zone " + zone.getName() - + " has overlapped with the subnet. Please specify a different gateway/netmask."); - } - } - } - } - private VlanVO commitVlanAndIpRange(final long zoneId, final long networkId, final long physicalNetworkId, final Long podId, final String startIP, final String endIP, - final String vlanGateway, final String vlanNetmask, final String vlanId, final Domain domain, final Account vlanOwner, final String vlanIp6Gateway, final String vlanIp6Cidr, - final boolean ipv4, final DataCenterVO zone, final VlanType vlanType, final String ipv6Range, final String ipRange, final boolean forSystemVms) { + final String vlanGateway, final String vlanNetmask, final String vlanId, final Domain domain, final Account vlanOwner, final String vlanIp6Gateway, final String vlanIp6Cidr, + final boolean ipv4, final DataCenterVO zone, final VlanType vlanType, final String ipv6Range, final String ipRange, final boolean forSystemVms) { return Transaction.execute(new TransactionCallback() { @Override public VlanVO doInTransaction(final TransactionStatus status) { @@ -4786,9 +4222,8 @@ public VlanVO doInTransaction(final TransactionStatus status) { // range final List ips = _publicIpAddressDao.listByVlanId(vlan.getId()); for (final IPAddressVO ip : ips) { - final boolean usageHidden = _ipAddrMgr.isUsageHidden(ip); UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, vlanOwner.getId(), ip.getDataCenterId(), ip.getId(), ip.getAddress().toString(), - ip.isSourceNat(), vlan.getVlanType().toString(), ip.getSystem(), usageHidden, ip.getClass().getName(), ip.getUuid()); + ip.isSourceNat(), vlan.getVlanType().toString(), ip.getSystem(), ip.getClass().getName(), ip.getUuid()); } // increment resource count for dedicated public ip's _resourceLimitMgr.incrementResourceCount(vlanOwner.getId(), ResourceType.public_ip, new Long(ips.size())); @@ -4807,271 +4242,6 @@ public VlanVO doInTransaction(final TransactionStatus status) { } - @Override - public Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws ConcurrentOperationException, - ResourceUnavailableException,ResourceAllocationException { - - return updateVlanAndPublicIpRange(cmd.getId(), cmd.getStartIp(),cmd.getEndIp(), cmd.getGateway(),cmd.getNetmask(), - cmd.getStartIpv6(), cmd.getEndIpv6(), cmd.getIp6Gateway(), cmd.getIp6Cidr(), cmd.isForSystemVms()); - } - - @DB - @ActionEvent(eventType = EventTypes.EVENT_VLAN_IP_RANGE_UPDATE, eventDescription = "update vlan ip Range", async - = false) - public Vlan updateVlanAndPublicIpRange(final long id, String startIp, - String endIp, - String gateway, - String netmask, - String startIpv6, - String endIpv6, - String ip6Gateway, - String ip6Cidr, - Boolean forSystemVms) throws ConcurrentOperationException { - - VlanVO vlanRange = _vlanDao.findById(id); - if (vlanRange == null) { - throw new InvalidParameterValueException("Please specify a valid IP range id."); - } - - final boolean ipv4 = vlanRange.getVlanGateway() != null; - final boolean ipv6 = vlanRange.getIp6Gateway() != null; - if (!ipv4) { - if (startIp != null || endIp != null || gateway != null || netmask != null) { - throw new InvalidParameterValueException("IPv4 is not support in this IP range."); - } - } - if (!ipv6) { - if (startIpv6 != null || endIpv6 != null || ip6Gateway != null || ip6Cidr != null) { - throw new InvalidParameterValueException("IPv6 is not support in this IP range."); - } - } - - final Boolean isRangeForSystemVM = checkIfVlanRangeIsForSystemVM(id); - if (forSystemVms != null && isRangeForSystemVM != forSystemVms) { - if (VlanType.DirectAttached.equals(vlanRange.getVlanType())) { - throw new InvalidParameterValueException("forSystemVms is not available for this IP range with vlan type: " + VlanType.DirectAttached); - } - // Check if range has already been dedicated - final List maps = _accountVlanMapDao.listAccountVlanMapsByVlan(id); - if (maps != null && !maps.isEmpty()) { - throw new InvalidParameterValueException("Specified Public IP range has already been dedicated to an account"); - } - - List domainmaps = _domainVlanMapDao.listDomainVlanMapsByVlan(id); - if (domainmaps != null && !domainmaps.isEmpty()) { - throw new InvalidParameterValueException("Specified Public IP range has already been dedicated to a domain"); - } - } - if (ipv4) { - updateVlanAndIpv4Range(id, vlanRange, startIp, endIp, gateway, netmask, isRangeForSystemVM, forSystemVms); - } - if (ipv6) { - updateVlanAndIpv6Range(id, vlanRange, startIpv6, endIpv6, ip6Gateway, ip6Cidr, isRangeForSystemVM, forSystemVms); - } - return _vlanDao.findById(id); - } - - private void updateVlanAndIpv4Range(final long id, final VlanVO vlanRange, - String startIp, - String endIp, - String gateway, - String netmask, - final Boolean isRangeForSystemVM, - final Boolean forSystemVms) { - final List listAllocatedIPs = _publicIpAddressDao.listByVlanIdAndState(id, IpAddress.State.Allocated); - - if (gateway != null && !gateway.equals(vlanRange.getVlanGateway()) && CollectionUtils.isNotEmpty(listAllocatedIPs)) { - throw new InvalidParameterValueException(String.format("Unable to change gateway to %s because some IPs are in use", gateway)); - } - if (netmask != null && !netmask.equals(vlanRange.getVlanNetmask()) && CollectionUtils.isNotEmpty(listAllocatedIPs)) { - throw new InvalidParameterValueException(String.format("Unable to change netmask to %s because some IPs are in use", netmask)); - } - - gateway = MoreObjects.firstNonNull(gateway, vlanRange.getVlanGateway()); - netmask = MoreObjects.firstNonNull(netmask, vlanRange.getVlanNetmask()); - - final String[] existingVlanIPRangeArray = vlanRange.getIpRange().split("-"); - final String currentStartIP = existingVlanIPRangeArray[0]; - final String currentEndIP = existingVlanIPRangeArray[1]; - - startIp = MoreObjects.firstNonNull(startIp, currentStartIP); - endIp = MoreObjects.firstNonNull(endIp, currentEndIP); - - final String cidr = NetUtils.ipAndNetMaskToCidr(gateway, netmask); - if (StringUtils.isEmpty(cidr)) { - throw new InvalidParameterValueException(String.format("Invalid gateway (%s) or netmask (%s)", gateway, netmask)); - } - final String cidrAddress = getCidrAddress(cidr); - final long cidrSize = getCidrSize(cidr); - - checkIpRange(startIp, endIp, cidrAddress, cidrSize); - - checkGatewayOverlap(startIp, endIp, gateway); - - checkAllocatedIpsAreWithinVlanRange(listAllocatedIPs, startIp, endIp, forSystemVms); - - try { - final String newStartIP = startIp; - final String newEndIP = endIp; - - VlanVO range = _vlanDao.acquireInLockTable(id, 30); - if (range == null) { - throw new CloudRuntimeException("Unable to acquire vlan configuration: " + id); - } - - if (s_logger.isDebugEnabled()) { - s_logger.debug("lock vlan " + id + " is acquired"); - } - - commitUpdateVlanAndIpRange(id, newStartIP, newEndIP, currentStartIP, currentEndIP, gateway, netmask,true, isRangeForSystemVM, forSystemVms); - - } catch (final Exception e) { - s_logger.error("Unable to edit VlanRange due to " + e.getMessage(), e); - throw new CloudRuntimeException("Failed to edit VlanRange. Please contact Cloud Support."); - } finally { - _vlanDao.releaseFromLockTable(id); - } - } - - private void updateVlanAndIpv6Range(final long id, final VlanVO vlanRange, - String startIpv6, - String endIpv6, - String ip6Gateway, - String ip6Cidr, - final Boolean isRangeForSystemVM, - final Boolean forSystemVms) { - final List listAllocatedIPs = _ipv6Dao.listByVlanIdAndState(id, IpAddress.State.Allocated); - - if (ip6Gateway != null && !ip6Gateway.equals(vlanRange.getIp6Gateway()) && (CollectionUtils.isNotEmpty(listAllocatedIPs) || CollectionUtils.isNotEmpty(ipv6Service.getAllocatedIpv6FromVlanRange(vlanRange)))) { - throw new InvalidParameterValueException(String.format("Unable to change ipv6 gateway to %s because some IPs are in use", ip6Gateway)); - } - if (ip6Cidr != null && !ip6Cidr.equals(vlanRange.getIp6Cidr()) && (CollectionUtils.isNotEmpty(listAllocatedIPs) || CollectionUtils.isNotEmpty(ipv6Service.getAllocatedIpv6FromVlanRange(vlanRange)))) { - throw new InvalidParameterValueException(String.format("Unable to change ipv6 cidr to %s because some IPs are in use", ip6Cidr)); - } - ip6Gateway = MoreObjects.firstNonNull(ip6Gateway, vlanRange.getIp6Gateway()); - ip6Cidr = MoreObjects.firstNonNull(ip6Cidr, vlanRange.getIp6Cidr()); - - final String[] existingVlanIPRangeArray = StringUtils.isNotEmpty(vlanRange.getIp6Range()) ? vlanRange.getIp6Range().split("-") : null; - final String currentStartIPv6 = existingVlanIPRangeArray != null ? existingVlanIPRangeArray[0] : null; - final String currentEndIPv6 = existingVlanIPRangeArray != null ? existingVlanIPRangeArray[1] : null; - - startIpv6 = ObjectUtils.allNull(startIpv6, currentStartIPv6) ? null : MoreObjects.firstNonNull(startIpv6, currentStartIPv6); - endIpv6 = ObjectUtils.allNull(endIpv6, currentEndIPv6) ? null : MoreObjects.firstNonNull(endIpv6, currentEndIPv6); - - _networkModel.checkIp6Parameters(startIpv6, endIpv6, ip6Gateway, ip6Cidr); - - if (!ObjectUtils.allNull(startIpv6, endIpv6) && ObjectUtils.anyNull(startIpv6, endIpv6)) { - throw new InvalidParameterValueException(String.format("Invalid IPv6 range %s-%s", startIpv6, endIpv6)); - } - if (ObjectUtils.allNotNull(startIpv6, endIpv6) && (!startIpv6.equals(currentStartIPv6) || !endIpv6.equals(currentEndIPv6))) { - checkAllocatedIpv6sAreWithinVlanRange(listAllocatedIPs, startIpv6, endIpv6); - } - - try { - VlanVO range = _vlanDao.acquireInLockTable(id, 30); - if (range == null) { - throw new CloudRuntimeException("Unable to acquire vlan configuration: " + id); - } - - if (s_logger.isDebugEnabled()) { - s_logger.debug("lock vlan " + id + " is acquired"); - } - - commitUpdateVlanAndIpRange(id, startIpv6, endIpv6, currentStartIPv6, currentEndIPv6, ip6Gateway, ip6Cidr, false, isRangeForSystemVM,forSystemVms); - - } catch (final Exception e) { - s_logger.error("Unable to edit VlanRange due to " + e.getMessage(), e); - throw new CloudRuntimeException("Failed to edit VlanRange. Please contact Cloud Support."); - } finally { - _vlanDao.releaseFromLockTable(id); - } - } - - private VlanVO commitUpdateVlanAndIpRange(final Long id, final String newStartIP, final String newEndIP, final String currentStartIP, final String currentEndIP, - final String gateway, final String netmask, - final boolean ipv4, final Boolean isRangeForSystemVM, final Boolean forSystemvms) { - - return Transaction.execute(new TransactionCallback() { - @Override - public VlanVO doInTransaction(final TransactionStatus status) { - VlanVO vlanRange = _vlanDao.findById(id); - s_logger.debug("Updating vlan range " + vlanRange.getId()); - if (ipv4) { - vlanRange.setIpRange(newStartIP + "-" + newEndIP); - vlanRange.setVlanGateway(gateway); - vlanRange.setVlanNetmask(netmask); - _vlanDao.update(vlanRange.getId(), vlanRange); - if (!updatePublicIPRange(newStartIP, currentStartIP, newEndIP, currentEndIP, vlanRange.getDataCenterId(), vlanRange.getId(), vlanRange.getNetworkId(), vlanRange.getPhysicalNetworkId(), isRangeForSystemVM, forSystemvms)) { - throw new CloudRuntimeException("Failed to update IPv4 range. Please contact Cloud Support."); - } - } else { - if (ObjectUtils.allNotNull(newStartIP, newEndIP)) { - vlanRange.setIp6Range(newStartIP + "-" + newEndIP); - } else { - vlanRange.setIp6Range(null); - } - vlanRange.setIp6Gateway(gateway); - vlanRange.setIp6Cidr(netmask); - _vlanDao.update(vlanRange.getId(), vlanRange); - } - return vlanRange; - } - }); - } - - private boolean checkIfVlanRangeIsForSystemVM(final long vlanId) { - List existingPublicIPs = _publicIpAddressDao.listByVlanId(vlanId); - if (CollectionUtils.isEmpty(existingPublicIPs)) { - return false; - } - boolean initialIsSystemVmValue = existingPublicIPs.get(0).isForSystemVms(); - for (IPAddressVO existingIPs : existingPublicIPs) { - if (initialIsSystemVmValue != existingIPs.isForSystemVms()) { - throw new CloudRuntimeException("Your \"For System VM\" value seems to be inconsistent with the rest of the records. Please contact Cloud Support"); - } - } - return initialIsSystemVmValue; - } - - private void checkAllocatedIpsAreWithinVlanRange - (List listAllocatedIPs, String startIp, String endIp, Boolean forSystemVms) { - Collections.sort(listAllocatedIPs, Comparator.comparing(IPAddressVO::getAddress)); - for (IPAddressVO allocatedIP : listAllocatedIPs) { - if ((StringUtils.isNotEmpty(startIp) && NetUtils.ip2Long(startIp) > NetUtils.ip2Long(allocatedIP.getAddress().addr())) - || (StringUtils.isNotEmpty(endIp) && NetUtils.ip2Long(endIp) < NetUtils.ip2Long(allocatedIP.getAddress().addr()))) { - throw new InvalidParameterValueException(String.format("The start IP address must be less than or equal to %s which is already in use. " - + "The end IP address must be greater than or equal to %s which is already in use. " - + "There are %d IPs already allocated in this range.", - listAllocatedIPs.get(0).getAddress(), listAllocatedIPs.get(listAllocatedIPs.size() - 1).getAddress(), listAllocatedIPs.size())); - } - if (forSystemVms != null && allocatedIP.isForSystemVms() != forSystemVms) { - throw new InvalidParameterValueException(String.format("IP %s is in use, cannot change forSystemVms of the IP range", allocatedIP.getAddress().addr())); - } - } - } - - private void checkAllocatedIpv6sAreWithinVlanRange(List listAllocatedIPs, String startIpv6, String endIpv6) { - Collections.sort(listAllocatedIPs, Comparator.comparing(UserIpv6AddressVO::getAddress)); - for (UserIpv6AddressVO allocatedIP : listAllocatedIPs) { - if ((StringUtils.isNotEmpty(startIpv6) - && IPv6Address.fromString(startIpv6).toBigInteger().compareTo(IPv6Address.fromString(allocatedIP.getAddress()).toBigInteger()) > 0) - || (StringUtils.isNotEmpty(endIpv6) - && IPv6Address.fromString(endIpv6).toBigInteger().compareTo(IPv6Address.fromString(allocatedIP.getAddress()).toBigInteger()) < 0)) { - throw new InvalidParameterValueException(String.format("The start IPv6 address must be less than or equal to %s which is already in use. " - + "The end IPv6 address must be greater than or equal to %s which is already in use. " - + "There are %d IPv6 addresses already allocated in this range.", - listAllocatedIPs.get(0).getAddress(), listAllocatedIPs.get(listAllocatedIPs.size() - 1).getAddress(), listAllocatedIPs.size())); - } - } - } - - private void checkGatewayOverlap(String startIp, String endIp, String gateway) { - if (NetUtils.ipRangesOverlap(startIp, endIp, gateway, gateway)) { - throw new InvalidParameterValueException("The gateway shouldn't overlap the new start/end ip " - + "addresses"); - } - } - @Override @DB public boolean deleteVlanAndPublicIpRange(final long userId, final long vlanDbId, final Account caller) { @@ -5125,8 +4295,7 @@ public boolean deleteVlanAndPublicIpRange(final long userId, final long vlanDbId throw new InvalidParameterValueException("Can't delete account specific vlan " + vlanDbId + " as ip " + ip + " belonging to the range has firewall rules applied. Cleanup the rules first"); } - if (ip.getAllocatedTime() != null) { - // This means IP is allocated + if (ip.getAllocatedTime() != null) {// This means IP is allocated // release public ip address here success = _ipAddrMgr.disassociatePublicIpAddress(ip.getId(), userId, caller); } @@ -5134,9 +4303,8 @@ public boolean deleteVlanAndPublicIpRange(final long userId, final long vlanDbId s_logger.warn("Some ip addresses failed to be released as a part of vlan " + vlanDbId + " removal"); } else { resourceCountToBeDecrement++; - final boolean usageHidden = _ipAddrMgr.isUsageHidden(ip); UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_RELEASE, acctVln.get(0).getAccountId(), ip.getDataCenterId(), ip.getId(), - ip.getAddress().toString(), ip.isSourceNat(), vlanRange.getVlanType().toString(), ip.getSystem(), usageHidden, ip.getClass().getName(), ip.getUuid()); + ip.getAddress().toString(), ip.isSourceNat(), vlanRange.getVlanType().toString(), ip.getSystem(), ip.getClass().getName(), ip.getUuid()); } } } finally { @@ -5157,16 +4325,12 @@ public boolean deleteVlanAndPublicIpRange(final long userId, final long vlanDbId throw new InvalidParameterValueException(allocIpCount + " Ips are in use. Cannot delete this vlan"); } } - List ipAddresses = ipv6Service.getAllocatedIpv6FromVlanRange(vlanRange); - if (CollectionUtils.isNotEmpty(ipAddresses)) { - throw new InvalidParameterValueException(String.format("%d IPv6 addresses are in use. Cannot delete this vlan", ipAddresses.size())); - } Transaction.execute(new TransactionCallbackNoReturn() { @Override public void doInTransactionWithoutResult(final TransactionStatus status) { _publicIpAddressDao.deletePublicIPRange(vlanDbId); - s_logger.debug(String.format("Delete Public IP Range (from user_ip_address, where vlan_db_id=%s)", vlanDbId)); + s_logger.debug(String.format("Delete Public IP Range (from user_ip_address, where vlan_db_d=%s)", vlanDbId)); _vlanDao.remove(vlanDbId); s_logger.debug(String.format("Mark vlan as Remove vlan (vlan_db_id=%s)", vlanDbId)); @@ -5280,11 +4444,10 @@ public Vlan dedicatePublicIpRange(final DedicatePublicIpRangeCmd cmd) throws Res final AccountVlanMapVO accountVlanMapVO = new AccountVlanMapVO(vlanOwner.getId(), vlan.getId()); _accountVlanMapDao.persist(accountVlanMapVO); - // generate usage event for dedication of every ip address in the range + // generate usage event for dedication of every ip address in the range for (final IPAddressVO ip : ips) { - final boolean usageHidden = _ipAddrMgr.isUsageHidden(ip); UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_ASSIGN, vlanOwner.getId(), ip.getDataCenterId(), ip.getId(), ip.getAddress().toString(), ip.isSourceNat(), - vlan.getVlanType().toString(), ip.getSystem(), usageHidden, ip.getClass().getName(), ip.getUuid()); + vlan.getVlanType().toString(), ip.getSystem(), ip.getClass().getName(), ip.getUuid()); } } else if (domain != null && !forSystemVms) { // Create an DomainVlanMapVO entry @@ -5317,10 +4480,7 @@ public boolean releasePublicIpRange(final ReleasePublicIpRangeCmd cmd) { public boolean releasePublicIpRange(final long vlanDbId, final long userId, final Account caller) { VlanVO vlan = _vlanDao.findById(vlanDbId); if(vlan == null) { - // Nothing to do if vlan can't be found - s_logger.warn(String.format("Skipping the process for releasing public IP range as could not find a VLAN with ID '%s' for Account '%s' and User '%s'." - ,vlanDbId, caller, userId)); - return true; + s_logger.warn("VLAN information for Account '" + caller + "', User '" + userId + "' VLAN '" + vlanDbId + "' is null. This is NPE situation."); } // Verify range is dedicated @@ -5380,22 +4540,19 @@ public boolean releasePublicIpRange(final long vlanDbId, final long userId, fina // generate usage events to remove dedication for every ip in the range that has been disassociated for (final IPAddressVO ip : ips) { if (!ipsInUse.contains(ip)) { - final boolean usageHidden = _ipAddrMgr.isUsageHidden(ip); UsageEventUtils.publishUsageEvent(EventTypes.EVENT_NET_IP_RELEASE, acctVln.get(0).getAccountId(), ip.getDataCenterId(), ip.getId(), ip.getAddress().toString(), - ip.isSourceNat(), vlan.getVlanType().toString(), ip.getSystem(), usageHidden, ip.getClass().getName(), ip.getUuid()); + ip.isSourceNat(), vlan.getVlanType().toString(), ip.getSystem(), ip.getClass().getName(), ip.getUuid()); } } // decrement resource count for dedicated public ip's _resourceLimitMgr.decrementResourceCount(acctVln.get(0).getAccountId(), ResourceType.public_ip, new Long(ips.size())); - success = true; + return true; } else if (isDomainSpecific && _domainVlanMapDao.remove(domainVlan.get(0).getId())) { s_logger.debug("Remove the vlan from domain_vlan_map successfully."); - success = true; + return true; } else { - success = false; + return false; } - - return success; } @DB @@ -5411,59 +4568,6 @@ public List doInTransaction(final TransactionStatus status) { } }); - return CollectionUtils.isEmpty(problemIps); - } - - @DB - protected boolean updatePublicIPRange(final String newStartIP, final String currentStartIP, final String newEndIP, final String currentEndIP, final long zoneId, final long vlanDbId, final long sourceNetworkid, final long physicalNetworkId, final boolean isRangeForSystemVM, final Boolean forSystemVms) { - long newStartIPLong = NetUtils.ip2Long(newStartIP); - long newEndIPLong = NetUtils.ip2Long(newEndIP); - long currentStartIPLong = NetUtils.ip2Long(currentStartIP); - long currentEndIPLong = NetUtils.ip2Long(currentEndIP); - - List currentIPRange = new ArrayList<>(); - List newIPRange = new ArrayList<>(); - while (newStartIPLong <= newEndIPLong) { - newIPRange.add(newStartIPLong); - newStartIPLong++; - } - while (currentStartIPLong <= currentEndIPLong) { - currentIPRange.add(currentStartIPLong); - currentStartIPLong++; - } - - final List problemIps = Transaction.execute(new TransactionCallback>() { - - @Override - public List doInTransaction(final TransactionStatus status) { - final IPRangeConfig config = new IPRangeConfig(); - Vector configResult = new Vector<>(); - List ipAddressesToAdd = new ArrayList(newIPRange); - ipAddressesToAdd.removeAll(currentIPRange); - if (ipAddressesToAdd.size() > 0) { - for (Long startIP : ipAddressesToAdd) { - configResult.addAll(config.savePublicIPRange(TransactionLegacy.currentTxn(), startIP, startIP, zoneId, vlanDbId, sourceNetworkid, physicalNetworkId, forSystemVms != null ? forSystemVms : isRangeForSystemVM)); - } - } - List ipAddressesToDelete = new ArrayList(currentIPRange); - ipAddressesToDelete.removeAll(newIPRange); - if (ipAddressesToDelete.size() > 0) { - for (Long startIP : ipAddressesToDelete) { - configResult.addAll(config.deletePublicIPRange(TransactionLegacy.currentTxn(), startIP, startIP, vlanDbId)); - } - } - if (forSystemVms != null && isRangeForSystemVM != forSystemVms) { - List ipAddressesToUpdate = new ArrayList(currentIPRange); - ipAddressesToUpdate.removeAll(ipAddressesToDelete); - if (ipAddressesToUpdate.size() > 0) { - for (Long startIP : ipAddressesToUpdate) { - configResult.addAll(config.updatePublicIPRange(TransactionLegacy.currentTxn(), startIP, startIP, vlanDbId, forSystemVms)); - } - } - } - return configResult; - } - }); return problemIps != null && problemIps.size() == 0; } @@ -5731,7 +4835,6 @@ public void checkZoneAccess(final Account caller, final DataCenter zone) { public NetworkOffering createNetworkOffering(final CreateNetworkOfferingCmd cmd) { final String name = cmd.getNetworkOfferingName(); final String displayText = cmd.getDisplayText(); - final NetUtils.InternetProtocol internetProtocol = NetUtils.InternetProtocol.fromValue(cmd.getInternetProtocol()); final String tags = cmd.getTags(); final String trafficTypeString = cmd.getTraffictype(); final boolean specifyVlan = cmd.getSpecifyVlan(); @@ -5746,12 +4849,13 @@ public NetworkOffering createNetworkOffering(final CreateNetworkOfferingCmd cmd) final Map detailsStr = cmd.getDetails(); final Boolean egressDefaultPolicy = cmd.getEgressDefaultPolicy(); Boolean forVpc = cmd.getForVpc(); + Boolean forTungsten = cmd.getForTungsten(); Integer maxconn = null; boolean enableKeepAlive = false; String servicePackageuuid = cmd.getServicePackageId(); final List domainIds = cmd.getDomainIds(); final List zoneIds = cmd.getZoneIds(); - final boolean enable = cmd.getEnable(); + // check if valid domain if (CollectionUtils.isNotEmpty(domainIds)) { for (final Long domainId: domainIds) { @@ -5797,16 +4901,6 @@ public NetworkOffering createNetworkOffering(final CreateNetworkOfferingCmd cmd) throw new InvalidParameterValueException("Invalid \"type\" parameter is given; can have Shared and Isolated values"); } - if (internetProtocol != null) { - if (!GuestType.Isolated.equals(guestType)) { - throw new InvalidParameterValueException(String.format("%s is supported only for %s guest type", ApiConstants.INTERNET_PROTOCOL, GuestType.Isolated)); - } - - if (!Ipv6Service.Ipv6OfferingCreationEnabled.value() && !NetUtils.InternetProtocol.IPv4.equals(internetProtocol)) { - throw new InvalidParameterValueException(String.format("Configuration %s needs to be enabled for creating IPv6 supported network offering", Ipv6Service.Ipv6OfferingCreationEnabled.key())); - } - } - // Verify availability for (final Availability avlb : Availability.values()) { if (avlb.name().equalsIgnoreCase(availabilityStr)) { @@ -5857,7 +4951,7 @@ public NetworkOffering createNetworkOffering(final CreateNetworkOfferingCmd cmd) if (service == Service.SecurityGroup) { // allow security group service for Shared networks only if (guestType != GuestType.Shared) { - throw new InvalidParameterValueException("Security group service is supported for network offerings with guest ip type " + GuestType.Shared); + throw new InvalidParameterValueException("Secrity group service is supported for network offerings with guest ip type " + GuestType.Shared); } final Set sgProviders = new HashSet(); sgProviders.add(Provider.SecurityGroupProvider); @@ -5913,6 +5007,10 @@ public NetworkOffering createNetworkOffering(final CreateNetworkOfferingCmd cmd) forVpc = true; } + if (forTungsten == null && Provider.Tungsten.equals(provider)){ + forTungsten = true; + } + if (service == Service.Dhcp) { dhcpProvider = provider; } @@ -6034,10 +5132,9 @@ public NetworkOffering createNetworkOffering(final CreateNetworkOfferingCmd cmd) forVpc = false; } - final NetworkOfferingVO offering = createNetworkOffering(name, displayText, trafficType, tags, specifyVlan, availability, networkRate, serviceProviderMap, false, guestType, false, - serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent, details, egressDefaultPolicy, maxconn, enableKeepAlive, forVpc, domainIds, zoneIds, enable, internetProtocol); + final NetworkOffering offering = createNetworkOffering(name, displayText, trafficType, tags, specifyVlan, availability, networkRate, serviceProviderMap, false, guestType, false, + serviceOfferingId, conserveMode, serviceCapabilityMap, specifyIpRanges, isPersistent, details, egressDefaultPolicy, maxconn, enableKeepAlive, forVpc, forTungsten, domainIds, zoneIds); CallContext.current().setEventDetails(" Id: " + offering.getId() + " Name: " + name); - CallContext.current().putContextParameter(NetworkOffering.class, offering.getId()); return offering; } @@ -6169,12 +5266,12 @@ void validateConnectivityServiceCapablities(final Network.GuestType guestType, f @Override @DB public NetworkOfferingVO createNetworkOffering(final String name, final String displayText, final TrafficType trafficType, String tags, final boolean specifyVlan, - final Availability availability, - final Integer networkRate, final Map> serviceProviderMap, final boolean isDefault, final GuestType type, final boolean systemOnly, - final Long serviceOfferingId, - final boolean conserveMode, final Map> serviceCapabilityMap, final boolean specifyIpRanges, final boolean isPersistent, - final Map details, final boolean egressDefaultPolicy, final Integer maxconn, final boolean enableKeepAlive, Boolean forVpc, - final List domainIds, final List zoneIds, final boolean enableOffering, final NetUtils.InternetProtocol internetProtocol) { + final Availability availability, + final Integer networkRate, final Map> serviceProviderMap, final boolean isDefault, final GuestType type, final boolean systemOnly, + final Long serviceOfferingId, + final boolean conserveMode, final Map> serviceCapabilityMap, final boolean specifyIpRanges, final boolean isPersistent, + final Map details, final boolean egressDefaultPolicy, final Integer maxconn, final boolean enableKeepAlive, Boolean forVpc, Boolean forTungsten, + final List domainIds, final List zoneIds) { String servicePackageUuid; String spDescription = null; @@ -6188,7 +5285,15 @@ public NetworkOfferingVO createNetworkOffering(final String name, final String d final String multicastRateStr = _configDao.getValue("multicast.throttling.rate"); final int multicastRate = multicastRateStr == null ? 10 : Integer.parseInt(multicastRateStr); - tags = com.cloud.utils.StringUtils.cleanupTags(tags); + tags = StringUtils.cleanupTags(tags); + + // specifyVlan should always be true for Shared network offerings + if (!specifyVlan && type == GuestType.Shared) { + Set connectivityProviders = serviceProviderMap != null ? serviceProviderMap.get(Service.Connectivity) : null; + if (CollectionUtils.isEmpty(connectivityProviders) || !_networkModel.providerSupportsCapability(connectivityProviders, Service.Connectivity, Capability.NoVlan)) { + throw new InvalidParameterValueException("SpecifyVlan should be true if network offering's type is " + type); + } + } // specifyIpRanges should always be true for Shared networks // specifyIpRanges can only be true for Isolated networks with no Source @@ -6336,9 +5441,7 @@ public NetworkOfferingVO createNetworkOffering(final String name, final String d offeringFinal.setServiceOfferingId(serviceOfferingId); } - if (enableOffering) { - offeringFinal.setState(NetworkOffering.State.Enabled); - } + offeringFinal.setForTungsten(forTungsten); //Set Service package id offeringFinal.setServicePackage(servicePackageUuid); @@ -6419,9 +5522,6 @@ public NetworkOfferingVO doInTransaction(final TransactionStatus status) { detailsVO.add(new NetworkOfferingDetailsVO(offering.getId(), Detail.zoneid, String.valueOf(zoneId), false)); } } - if (internetProtocol != null) { - detailsVO.add(new NetworkOfferingDetailsVO(offering.getId(), Detail.internetProtocol, String.valueOf(internetProtocol), true)); - } if (!detailsVO.isEmpty()) { networkOfferingDetailsDao.saveDetails(detailsVO); } @@ -6472,8 +5572,9 @@ protected void validateNtwkOffDetails(final Map details, final M @Override public Pair, Integer> searchForNetworkOfferings(final ListNetworkOfferingsCmd cmd) { - final Filter searchFilter = new Filter(NetworkOfferingJoinVO.class, "sortKey", QueryService.SortKeyAscending.value(), null, null); - searchFilter.addOrderBy(NetworkOfferingJoinVO.class, "id", true); + Boolean isAscending = Boolean.parseBoolean(_configDao.getValue("sortkey.algorithm")); + isAscending = isAscending == null ? Boolean.TRUE : isAscending; + final Filter searchFilter = new Filter(NetworkOfferingJoinVO.class, "sortKey", isAscending, null, null); final Account caller = CallContext.current().getCallingAccount(); final SearchCriteria sc = networkOfferingJoinDao.createSearchCriteria(); @@ -6625,16 +5726,16 @@ public Pair, Integer> searchForNetworkOfferings( final List offerings = networkOfferingJoinDao.search(sc, searchFilter); // Remove offerings that are not associated with caller's domain or domainId passed - if ((caller.getType() != Account.Type.ADMIN || domainId != null) && CollectionUtils.isNotEmpty(offerings)) { + if ((caller.getType() != Account.ACCOUNT_TYPE_ADMIN || domainId != null) && CollectionUtils.isNotEmpty(offerings)) { ListIterator it = offerings.listIterator(); while (it.hasNext()) { NetworkOfferingJoinVO offering = it.next(); - if (StringUtils.isNotEmpty(offering.getDomainId())) { + if (!Strings.isNullOrEmpty(offering.getDomainId())) { boolean toRemove = false; String[] domainIdsArray = offering.getDomainId().split(","); for (String domainIdString : domainIdsArray) { Long dId = Long.valueOf(domainIdString.trim()); - if (caller.getType() != Account.Type.ADMIN && + if (caller.getType() != Account.ACCOUNT_TYPE_ADMIN && !_domainDao.isChildDomain(dId, caller.getDomainId())) { toRemove = true; break; @@ -6732,14 +5833,14 @@ public Pair, Integer> searchForNetworkOfferings( } // Now apply pagination - final List wPagination = com.cloud.utils.StringUtils.applyPagination(supportedOfferings, cmd.getStartIndex(), cmd.getPageSizeVal()); + final List wPagination = StringUtils.applyPagination(supportedOfferings, cmd.getStartIndex(), cmd.getPageSizeVal()); if (wPagination != null) { final Pair, Integer> listWPagination = new Pair, Integer>(wPagination, supportedOfferings.size()); return listWPagination; } return new Pair, Integer>(supportedOfferings, supportedOfferings.size()); } else { - final List wPagination = com.cloud.utils.StringUtils.applyPagination(offerings, cmd.getStartIndex(), cmd.getPageSizeVal()); + final List wPagination = StringUtils.applyPagination(offerings, cmd.getStartIndex(), cmd.getPageSizeVal()); if (wPagination != null) { final Pair, Integer> listWPagination = new Pair<>(wPagination, offerings.size()); return listWPagination; @@ -6782,7 +5883,6 @@ public boolean deleteNetworkOffering(final DeleteNetworkOfferingCmd cmd) { + "To make the network offering unavaiable, disable it"); } - annotationDao.removeByEntityType(AnnotationService.EntityType.NETWORK_OFFERING.name(), offering.getUuid()); if (_networkOfferingDao.remove(offeringId)) { return true; } else { @@ -7110,9 +6210,9 @@ public List listNetworkOfferings(final TrafficType tr return _networkOfferingDao.search(sc, searchFilter); } - @Override - @DB - public boolean releaseDomainSpecificVirtualRanges(final long domainId) { + @Override + @DB + public boolean releaseDomainSpecificVirtualRanges(final long domainId) { final List maps = _domainVlanMapDao.listDomainVlanMapsByDomain(domainId); if (CollectionUtils.isNotEmpty(maps)) { try { @@ -7452,46 +6552,6 @@ public String getConfigComponentName() { @Override public ConfigKey[] getConfigKeys() { - return new ConfigKey[] {SystemVMUseLocalStorage, IOPS_MAX_READ_LENGTH, IOPS_MAX_WRITE_LENGTH, - BYTES_MAX_READ_LENGTH, BYTES_MAX_WRITE_LENGTH, ADD_HOST_ON_SERVICE_RESTART_KVM, SET_HOST_DOWN_TO_MAINTENANCE, VM_SERVICE_OFFERING_MAX_CPU_CORES, - VM_SERVICE_OFFERING_MAX_RAM_SIZE, VM_USERDATA_MAX_LENGTH, MIGRATE_VM_ACROSS_CLUSTERS, - ENABLE_ACCOUNT_SETTINGS_FOR_DOMAIN, ENABLE_DOMAIN_SETTINGS_FOR_CHILD_DOMAIN - }; - } - - static class ParamCountPair { - private Long id; - private int paramCount; - private String scope; - - public ParamCountPair(Long id, int paramCount, String scope) { - this.id = id; - this.paramCount = paramCount; - this.scope = scope; - } - - public Long getId() { - return id; - } - - public void setId(Long id) { - this.id = id; - } - - public int getParamCount() { - return paramCount; - } - - public void setParamCount(int paramCount) { - this.paramCount = paramCount; - } - - public String getScope() { - return scope; - } - - public void setScope(String scope) { - this.scope = scope; - } + return new ConfigKey[] {SystemVMUseLocalStorage, IOPS_MAX_READ_LENGTH, IOPS_MAX_WRITE_LENGTH, BYTES_MAX_READ_LENGTH, BYTES_MAX_WRITE_LENGTH}; } } diff --git a/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java b/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java index 2f7051154c84..0d67a3fe9804 100644 --- a/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java +++ b/server/src/main/java/com/cloud/network/guru/ExternalGuestNetworkGuru.java @@ -17,15 +17,6 @@ package com.cloud.network.guru; -import java.util.List; - -import javax.inject.Inject; - -import org.apache.cloudstack.api.ApiCommandResourceType; -import org.apache.cloudstack.context.CallContext; -import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; -import org.apache.log4j.Logger; - import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; import com.cloud.dc.dao.DataCenterDao; @@ -36,12 +27,9 @@ import com.cloud.event.EventVO; import com.cloud.exception.InsufficientAddressCapacityException; import com.cloud.exception.InsufficientVirtualNetworkCapacityException; -import com.cloud.exception.InvalidParameterValueException; import com.cloud.network.IpAddressManager; import com.cloud.network.Network; import com.cloud.network.Network.GuestType; -import com.cloud.network.Network.Provider; -import com.cloud.network.Network.Service; import com.cloud.network.Network.State; import com.cloud.network.Networks.BroadcastDomainType; import com.cloud.network.PhysicalNetwork; @@ -59,18 +47,21 @@ import com.cloud.network.rules.dao.PortForwardingRulesDao; import com.cloud.offering.NetworkOffering; import com.cloud.user.Account; -import com.cloud.utils.Pair; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.utils.net.Ip; import com.cloud.utils.net.NetUtils; -import com.cloud.vm.Nic; import com.cloud.vm.Nic.ReservationStrategy; import com.cloud.vm.NicProfile; import com.cloud.vm.NicVO; import com.cloud.vm.ReservationContext; -import com.cloud.vm.VirtualMachine; import com.cloud.vm.VirtualMachineProfile; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.engine.orchestration.service.NetworkOrchestrationService; +import org.apache.log4j.Logger; + +import javax.inject.Inject; +import java.util.List; public class ExternalGuestNetworkGuru extends GuestNetworkGuru { private static final Logger s_logger = Logger.getLogger(ExternalGuestNetworkGuru.class); @@ -113,7 +104,7 @@ && isMyIsolationMethod(physicalNetwork) && !offering.isSystemOnly()) { @Override public Network design(NetworkOffering offering, DeploymentPlan plan, Network userSpecified, Account owner) { - if (_networkModel.areServicesSupportedByNetworkOffering(offering.getId(), Network.Service.Connectivity)) { + if (_networkModel.areServicesSupportedByNetworkOffering(offering.getId(), Network.Service.Connectivity) || offering.isForTungsten()) { return null; } @@ -124,27 +115,13 @@ public Network design(NetworkOffering offering, DeploymentPlan plan, Network use /* In order to revert userSpecified network setup */ config.setState(State.Allocated); } - if (userSpecified == null) { - return config; - } - if ((userSpecified.getIp6Cidr() == null && userSpecified.getIp6Gateway() != null) || - (userSpecified.getIp6Cidr() != null && userSpecified.getIp6Gateway() == null)) { - throw new InvalidParameterValueException("ip6gateway and ip6cidr must be specified together."); - } - if (userSpecified.getIp6Cidr() != null) { - config.setIp6Cidr(userSpecified.getIp6Cidr()); - config.setIp6Gateway(userSpecified.getIp6Gateway()); - } - if (userSpecified.getRouterIpv6() != null) { - config.setRouterIpv6(userSpecified.getRouterIpv6()); - } return config; } @Override public Network implement(Network config, NetworkOffering offering, DeployDestination dest, ReservationContext context) - throws InsufficientVirtualNetworkCapacityException { + throws InsufficientVirtualNetworkCapacityException { assert (config.getState() == State.Implementing) : "Why are we implementing " + config; if (_networkModel.areServicesSupportedInNetwork(config.getId(), Network.Service.Connectivity)) { @@ -157,15 +134,15 @@ public Network implement(Network config, NetworkOffering offering, DeployDestina DataCenter zone = dest.getDataCenter(); NetworkVO implemented = - new NetworkVO(config.getTrafficType(), config.getMode(), config.getBroadcastDomainType(), config.getNetworkOfferingId(), State.Allocated, - config.getDataCenterId(), config.getPhysicalNetworkId(), offering.isRedundantRouter()); + new NetworkVO(config.getTrafficType(), config.getMode(), config.getBroadcastDomainType(), config.getNetworkOfferingId(), State.Allocated, + config.getDataCenterId(), config.getPhysicalNetworkId(), offering.isRedundantRouter()); // Get a vlan tag int vlanTag; if (config.getBroadcastUri() == null) { String vnet = - _dcDao.allocateVnet(zone.getId(), config.getPhysicalNetworkId(), config.getAccountId(), context.getReservationId(), - UseSystemGuestVlans.valueIn(config.getAccountId())); + _dcDao.allocateVnet(zone.getId(), config.getPhysicalNetworkId(), config.getAccountId(), context.getReservationId(), + UseSystemGuestVlans.valueIn(config.getAccountId())); try { // when supporting more types of networks this need to become @@ -177,7 +154,7 @@ public Network implement(Network config, NetworkOffering offering, DeployDestina implemented.setBroadcastUri(BroadcastDomainType.Vlan.toUri(vlanTag)); ActionEventUtils.onCompletedActionEvent(CallContext.current().getCallingUserId(), config.getAccountId(), EventVO.LEVEL_INFO, - EventTypes.EVENT_ZONE_VLAN_ASSIGN, "Assigned Zone Vlan: " + vnet + " Network Id: " + config.getId(), config.getId(), ApiCommandResourceType.Network.toString(), 0); + EventTypes.EVENT_ZONE_VLAN_ASSIGN, "Assigned Zone Vlan: " + vnet + " Network Id: " + config.getId(), 0); } else { vlanTag = Integer.parseInt(BroadcastDomainType.getValue(config.getBroadcastUri())); implemented.setBroadcastUri(config.getBroadcastUri()); @@ -268,7 +245,7 @@ public Network implement(Network config, NetworkOffering offering, DeployDestina @Override public NicProfile allocate(Network config, NicProfile nic, VirtualMachineProfile vm) throws InsufficientVirtualNetworkCapacityException, - InsufficientAddressCapacityException { + InsufficientAddressCapacityException { if (_networkModel.networkIsConfiguredForExternalNetworking(config.getDataCenterId(), config.getId()) && nic != null && nic.getRequestedIPv4() != null) { throw new CloudRuntimeException("Does not support custom ip allocation at this time: " + nic); @@ -284,17 +261,6 @@ public NicProfile allocate(Network config, NicProfile nic, VirtualMachineProfile profile.setIPv4Netmask(null); } - if (config.getVpcId() == null && vm.getType() == VirtualMachine.Type.DomainRouter) { - boolean isPublicNetwork = _networkModel.isProviderSupportServiceInNetwork(config.getId(), Service.SourceNat, Provider.VirtualRouter); - if (!isPublicNetwork) { - Nic placeholderNic = _networkModel.getPlaceholderNicForRouter(config, null); - if (placeholderNic == null) { - s_logger.debug("Saving placeholder nic with ip4 address " + profile.getIPv4Address() + - " and ipv6 address " + profile.getIPv6Address() + " for the network " + config); - _networkMgr.savePlaceholderNic(config, profile.getIPv4Address(), profile.getIPv6Address(), VirtualMachine.Type.DomainRouter); - } - } - } return profile; } @@ -314,7 +280,7 @@ public void deallocate(Network config, NicProfile nic, VirtualMachineProfile vm) @Override public void reserve(NicProfile nic, Network config, VirtualMachineProfile vm, DeployDestination dest, ReservationContext context) - throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { assert (nic.getReservationStrategy() == ReservationStrategy.Start) : "What can I do for nics that are not allocated at start? "; DataCenter dc = _dcDao.findById(config.getDataCenterId()); @@ -322,9 +288,8 @@ public void reserve(NicProfile nic, Network config, VirtualMachineProfile vm, De if (_networkModel.networkIsConfiguredForExternalNetworking(config.getDataCenterId(), config.getId())) { nic.setBroadcastUri(config.getBroadcastUri()); nic.setIsolationUri(config.getBroadcastUri()); - Pair dns = _networkModel.getNetworkIp4Dns(config, dc); - nic.setIPv4Dns1(dns.first()); - nic.setIPv4Dns2(dns.second()); + nic.setIPv4Dns1(dc.getDns1()); + nic.setIPv4Dns2(dc.getDns2()); nic.setIPv4Netmask(NetUtils.cidr2Netmask(config.getCidr())); long cidrAddress = NetUtils.ip2Long(config.getCidr().split("/")[0]); int cidrSize = getGloballyConfiguredCidrSize(); diff --git a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java index 55944d67efab..e126d8026ffb 100644 --- a/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java +++ b/server/src/test/java/com/cloud/vpc/MockConfigurationManagerImpl.java @@ -23,17 +23,12 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import org.apache.cloudstack.api.command.admin.config.ResetCfgCmd; import org.apache.cloudstack.api.command.admin.config.UpdateCfgCmd; -import org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.CreateManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.CreateNetworkOfferingCmd; -import org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6PrefixCmd; import org.apache.cloudstack.api.command.admin.network.DeleteManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.network.DeleteNetworkOfferingCmd; -import org.apache.cloudstack.api.command.admin.network.ListGuestNetworkIpv6PrefixesCmd; import org.apache.cloudstack.api.command.admin.network.UpdateNetworkOfferingCmd; -import org.apache.cloudstack.api.command.admin.network.UpdatePodManagementNetworkIpRangeCmd; import org.apache.cloudstack.api.command.admin.offering.CreateDiskOfferingCmd; import org.apache.cloudstack.api.command.admin.offering.CreateServiceOfferingCmd; import org.apache.cloudstack.api.command.admin.offering.DeleteDiskOfferingCmd; @@ -49,7 +44,6 @@ import org.apache.cloudstack.api.command.admin.vlan.DedicatePublicIpRangeCmd; import org.apache.cloudstack.api.command.admin.vlan.DeleteVlanIpRangeCmd; import org.apache.cloudstack.api.command.admin.vlan.ReleasePublicIpRangeCmd; -import org.apache.cloudstack.api.command.admin.vlan.UpdateVlanIpRangeCmd; import org.apache.cloudstack.api.command.admin.zone.CreateZoneCmd; import org.apache.cloudstack.api.command.admin.zone.DeleteZoneCmd; import org.apache.cloudstack.api.command.admin.zone.UpdateZoneCmd; @@ -64,7 +58,6 @@ import com.cloud.dc.ClusterVO; import com.cloud.dc.DataCenter; import com.cloud.dc.DataCenter.NetworkType; -import com.cloud.dc.DataCenterGuestIpv6Prefix; import com.cloud.dc.DataCenterVO; import com.cloud.dc.HostPodVO; import com.cloud.dc.Pod; @@ -90,7 +83,6 @@ import com.cloud.user.Account; import com.cloud.utils.Pair; import com.cloud.utils.component.ManagerBase; -import com.cloud.utils.net.NetUtils; @Component public class MockConfigurationManagerImpl extends ManagerBase implements ConfigurationManager, ConfigurationService { @@ -211,41 +203,6 @@ public void deletePodIpRange(DeleteManagementNetworkIpRangeCmd cmd) throws Resou return; } - /* (non-Javadoc) - * @see com.cloud.configuration.ConfigurationService#updatePodIpRange(org.apache.cloudstack.api.command.admin.network.UpdatePodManagementNetworkIpRangeCmd) - */ - public void updatePodIpRange(final UpdatePodManagementNetworkIpRangeCmd cmd) throws ConcurrentOperationException { - // TODO Auto-generated method stub - return; - } - - /* (non-Javadoc) - * @see com.cloud.configuration.ConfigurationService#createDataCenterGuestIpv6Prefix(org.apache.cloudstack.api.command.admin.network.CreateGuestNetworkIpv6PrefixCmd) - */ - @Override - public DataCenterGuestIpv6Prefix createDataCenterGuestIpv6Prefix(CreateGuestNetworkIpv6PrefixCmd cmd) { - // TODO Auto-generated method stub - return null; - } - - /* (non-Javadoc) - * @see com.cloud.configuration.ConfigurationService#listDataCenterGuestIpv6Prefixes(org.apache.cloudstack.api.command.admin.network.ListGuestNetworkIpv6PrefixesCmd) - */ - @Override - public List listDataCenterGuestIpv6Prefixes(ListGuestNetworkIpv6PrefixesCmd cmd) { - // TODO Auto-generated method stub - return null; - } - - /* (non-Javadoc) - * @see com.cloud.configuration.ConfigurationService#deleteDataCenterGuestIpv6Prefix(org.apache.cloudstack.api.command.admin.network.DeleteGuestNetworkIpv6RangeCmd) - */ - @Override - public boolean deleteDataCenterGuestIpv6Prefix(DeleteGuestNetworkIpv6PrefixCmd cmd) { - // TODO Auto-generated method stub - return true; - } - /* (non-Javadoc) * @see com.cloud.configuration.ConfigurationService#editPod(org.apache.cloudstack.api.commands.UpdatePodCmd) */ @@ -296,18 +253,7 @@ public boolean deleteZone(DeleteZoneCmd cmd) { */ @Override public Vlan createVlanAndPublicIpRange(CreateVlanIpRangeCmd cmd) throws InsufficientCapacityException, ConcurrentOperationException, ResourceUnavailableException, - ResourceAllocationException { - // TODO Auto-generated method stub - return null; - } - - /* (non-Javadoc) - * @see com.cloud.configuration.ConfigurationService#updateVlanAndPublicIpRange(org.apache.cloudstack.api - * .commands.UpdateVlanIpRangeCmd) - */ - @Override - public Vlan updateVlanAndPublicIpRange(UpdateVlanIpRangeCmd cmd) throws ConcurrentOperationException, - ResourceUnavailableException, ResourceAllocationException{ + ResourceAllocationException { // TODO Auto-generated method stub return null; } @@ -501,7 +447,7 @@ public String updateConfiguration(long userId, String name, String category, Str */ @Override public HostPodVO createPod(long userId, String podName, long zoneId, String gateway, String cidr, String startIp, String endIp, String allocationState, - boolean skipGatewayOverlapCheck) { + boolean skipGatewayOverlapCheck) { // TODO Auto-generated method stub return null; } @@ -540,8 +486,7 @@ public void checkDiskOfferingAccess(Account caller, DiskOffering dof, DataCenter public NetworkOfferingVO createNetworkOffering(String name, String displayText, TrafficType trafficType, String tags, boolean specifyVlan, Availability availability, Integer networkRate, Map> serviceProviderMap, boolean isDefault, GuestType type, boolean systemOnly, Long serviceOfferingId, boolean conserveMode, Map> serviceCapabilityMap, boolean specifyIpRanges, boolean isPersistent, - Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, - List domainIds, List zoneIds, boolean enableOffering, NetUtils.InternetProtocol internetProtocol) { + Map details, boolean egressDefaultPolicy, Integer maxconn, boolean enableKeepAlive, Boolean forVpc, Boolean forTungsten, List domainIds, List zoneIds) { // TODO Auto-generated method stub return null; } @@ -551,8 +496,8 @@ public NetworkOfferingVO createNetworkOffering(String name, String displayText, */ @Override public Vlan createVlanAndPublicIpRange(long zoneId, long networkId, long physicalNetworkId, boolean forVirtualNetwork, boolean forSystemVms, Long podId, String startIP, String endIP, - String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanGatewayv6, String vlanCidrv6) - throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException { + String vlanGateway, String vlanNetmask, String vlanId, boolean bypassVlanOverlapCheck, Domain domain, Account vlanOwner, String startIPv6, String endIPv6, String vlanGatewayv6, String vlanCidrv6) + throws InsufficientCapacityException, ConcurrentOperationException, InvalidParameterValueException { // TODO Auto-generated method stub return null; } @@ -625,8 +570,8 @@ public AllocationState findClusterAllocationState(ClusterVO cluster) { */ @Override public DataCenterVO createZone(long userId, String zoneName, String dns1, String dns2, String internalDns1, String internalDns2, String guestCidr, String domain, - Long domainId, NetworkType zoneType, String allocationState, String networkDomain, boolean isSecurityGroupEnabled, boolean isLocalStorageEnabled, String ip6Dns1, - String ip6Dns2) { + Long domainId, NetworkType zoneType, String allocationState, String networkDomain, boolean isSecurityGroupEnabled, boolean isLocalStorageEnabled, String ip6Dns1, + String ip6Dns2) { // TODO Auto-generated method stub return null; } @@ -649,10 +594,4 @@ public Domain getVlanDomain(long vlanId) { return null; } - @Override - public Pair resetConfiguration(ResetCfgCmd cmd) throws InvalidParameterValueException { - // TODO Auto-generated method stub - return null; - } - } diff --git a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java index 16a036467083..8a47c25d0924 100644 --- a/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java +++ b/server/src/test/java/org/apache/cloudstack/networkoffering/CreateNetworkOfferingTest.java @@ -28,7 +28,6 @@ import javax.inject.Inject; -import org.apache.cloudstack.annotation.dao.AnnotationDao; import org.apache.cloudstack.context.CallContext; import org.apache.cloudstack.framework.config.dao.ConfigurationDao; import org.apache.cloudstack.framework.config.impl.ConfigurationVO; @@ -101,9 +100,6 @@ public class CreateNetworkOfferingTest extends TestCase { @Inject LoadBalancerVMMapDao _loadBalancerVMMapDao; - @Inject - AnnotationDao annotationDao; - @Override @Before public void setUp() { @@ -131,24 +127,24 @@ public void tearDown() { @Test public void createSharedNtwkOffWithVlan() { NetworkOfferingVO off = - configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false, null, false, null, true, false, null, null, false, null); + configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, + null, false, null, true, false, null, false, null, true, false, false,null, null); assertNotNull("Shared network offering with specifyVlan=true failed to create ", off); } - @Test + @Test(expected=InvalidParameterValueException.class) public void createSharedNtwkOffWithNoVlan() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, false, Availability.Optional, 200, null, false, Network.GuestType.Shared, - false, null, false, null, true, false, null, false, null, true, false, null, null, false, null); - assertNotNull("Shared network offering with specifyVlan=false was created", off); + false, null, false, null, true, false, null, false, null, true, false, false,null, null); + assertNull("Shared network offering with specifyVlan=false was created", off); } @Test public void createSharedNtwkOffWithSpecifyIpRanges() { NetworkOfferingVO off = - configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, - null, false, null, true, false, null, false, null, true, false, null, null, false, null); + configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, false, + null, false, null, true, false, null, false, null, true, false, false,null, null); assertNotNull("Shared network offering with specifyIpRanges=true failed to create ", off); } @@ -157,7 +153,7 @@ public void createSharedNtwkOffWithSpecifyIpRanges() { public void createSharedNtwkOffWithoutSpecifyIpRanges() { NetworkOfferingVO off = configMgr.createNetworkOffering("shared", "shared", TrafficType.Guest, null, true, Availability.Optional, 200, null, false, Network.GuestType.Shared, - false, null, false, null, false, false, null, false, null, true, false, null, null, false, null); + false, null, false, null, false, false, null, false, null, true, false, false,null, null); assertNull("Shared network offering with specifyIpRanges=false was created", off); } @@ -169,8 +165,8 @@ public void createIsolatedNtwkOffWithNoVlan() { vrProvider.add(Provider.VirtualRouter); serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = - configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, null, null, false, null); + configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, false,null, null); assertNotNull("Isolated network offering with specifyIpRanges=false failed to create ", off); } @@ -182,8 +178,8 @@ public void createIsolatedNtwkOffWithVlan() { vrProvider.add(Provider.VirtualRouter); serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = - configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, null, null, false, null); + configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, false, false,null, null); assertNotNull("Isolated network offering with specifyVlan=true wasn't created", off); } @@ -196,7 +192,7 @@ public void createIsolatedNtwkOffWithSpecifyIpRangesAndSourceNat() { serviceProviderMap.put(Network.Service.SourceNat, vrProvider); NetworkOfferingVO off = configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, null, null, false, null); + Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, false,null, null); assertNull("Isolated network offering with specifyIpRanges=true and source nat service enabled, was created", off); } @@ -206,8 +202,8 @@ public void createIsolatedNtwkOffWithSpecifyIpRangesAndNoSourceNat() { Map> serviceProviderMap = new HashMap>(); Set vrProvider = new HashSet(); NetworkOfferingVO off = - configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, null, null, false, null); + configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, false, Availability.Optional, 200, serviceProviderMap, false, + Network.GuestType.Isolated, false, null, false, null, true, false, null, false, null, true, false, false,null, null); assertNotNull("Isolated network offering with specifyIpRanges=true and with no sourceNatService, failed to create", off); } @@ -224,8 +220,8 @@ public void createVpcNtwkOff() { serviceProviderMap.put(Network.Service.Gateway, vrProvider); serviceProviderMap.put(Network.Service.Lb, vrProvider); NetworkOfferingVO off = - configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null, false, null); + configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false,null, null); // System.out.println("Creating Vpc Network Offering"); assertNotNull("Vpc Isolated network offering with Vpc provider ", off); } @@ -244,8 +240,8 @@ public void createVpcNtwkOffWithNetscaler() { serviceProviderMap.put(Network.Service.Gateway, vrProvider); serviceProviderMap.put(Network.Service.Lb, lbProvider); NetworkOfferingVO off = - configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, - Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, null, null, false, null); + configMgr.createNetworkOffering("isolated", "isolated", TrafficType.Guest, null, true, Availability.Optional, 200, serviceProviderMap, false, + Network.GuestType.Isolated, false, null, false, null, false, false, null, false, null, true, true, false,null, null); // System.out.println("Creating Vpc Network Offering"); assertNotNull("Vpc Isolated network offering with Vpc and Netscaler provider ", off); } diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index 6bad7cbe9050..c891621d6778 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -91,6 +91,7 @@ 'createTungstenInstanceIp' : 'Tungsten', 'listTungstenVirtualMachines' : 'Tungsten', 'listTungstenVmInterfaces' : 'Tungsten', + 'listTungstenVirtualRouters' : 'Tungsten', 'Vpn': 'VPN', 'Limit': 'Limit', 'ResourceCount': 'Limit', diff --git a/ui/l10n/en.js b/ui/l10n/en.js new file mode 100644 index 000000000000..52c7b256f2cd --- /dev/null +++ b/ui/l10n/en.js @@ -0,0 +1,2492 @@ +// 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. +var dictionary = { + "ICMP.code":"ICMP Code", + "ICMP.code.desc": "Please specify -1 if you want to allow all ICMP codes", + "ICMP.type":"ICMP Type", + "ICMP.type.desc": "Please specify -1 if you want to allow all ICMP types.", + "changed.item.properties":"Changed item properties", + "confirm.enable.s3":"Please fill in the following information to enable support for S3-backed Secondary Storage", + "confirm.enable.swift":"Please fill in the following information to enable support for Swift", + "error.could.not.change.your.password.because.non.native.user":"Error could not change your password because user is not a native CloudStack user.", + "error.could.not.enable.zone":"Could not enable zone", + "error.installWizard.message":"Something went wrong; you may go back and correct any errors", + "error.invalid.username.password": "Invalid username or password.

This could also be a restriction on the IP address you are connecting from.", + "error.login":"Your username/password does not match our records.", + "error.menu.select":"Unable to perform action due to no items being selected.", + "error.mgmt.server.inaccessible":"The Management Server is unaccessible. Please try again later.", + "error.password.not.match":"The password fields do not match", + "error.please.specify.physical.network.tags":"Network offerings is not available until you specify tags for this physical network.", + "error.session.expired":"Your session has expired.", + "error.something.went.wrong.please.correct.the.following":"Something went wrong; please correct the following", + "error.unable.to.reach.management.server":"Unable to reach Management Server", + "error.unresolved.internet.name":"Your internet name cannot be resolved.", + "force.delete":"Force Delete", + "force.delete.domain.warning":"Warning: Choosing this option will cause the deletion of all child domains and all associated accounts and their resources.", + "force.remove":"Force Remove", + "force.remove.host.warning":"Warning: Choosing this option will cause CloudStack to forcefully stop all running virtual machines before removing this host from the cluster.", + "force.stop":"Force Stop", + "force.stop.instance.warning":"Warning: Forcing a stop on this instance should be your last option. It can lead to data loss as well as inconsistent behavior of the virtual machine state.", + "hint.no.host.tags":"No host tags found", + "hint.no.storage.tags":"No storage tags found", + "hint.type.part.host.tag":"Type in part of a host tag", + "hint.type.part.storage.tag":"Type in part of a storage tag", + "image.directory":"Image Directory", + "inline":"Inline", + "instances.actions.reboot.label":"Reboot instance", + "label.async.backup":"Async Backup", + "label.CIDR.list":"CIDR list", + "label.CIDR.of.destination.network":"CIDR of destination network", + "label.CPU.cap":"CPU Cap", + "label.DHCP.server.type":"DHCP Server Type", + "label.DNS.domain.for.guest.networks":"DNS domain for Guest Networks", + "label.ESP.encryption":"ESP Encryption", + "label.ESP.hash":"ESP Hash", + "label.ESP.lifetime":"ESP Lifetime (second)", + "label.ESP.policy":"ESP policy", + "label.import.backup.offering":"Import Backup Offering", + "label.IKE.DH":"IKE DH", + "label.IKE.encryption":"IKE Encryption", + "label.IKE.hash":"IKE Hash", + "label.IKE.lifetime":"IKE lifetime (second)", + "label.IKE.policy":"IKE policy", + "label.IPsec.preshared.key":"IPsec Preshared-Key", + "label.LB.isolation":"LB isolation", + "label.LUN.number":"LUN #", + "label.PA":"Palo Alto", + "label.PA.log.profile":"Palo Alto Log Profile", + "label.PA.threat.profile":"Palo Alto Threat Profile", + "label.PING.CIFS.password":"PING CIFS password", + "label.PING.CIFS.username":"PING CIFS username", + "label.PING.dir":"PING Directory", + "label.PING.storage.IP":"PING storage IP", + "label.PreSetup":"PreSetup", + "label.Pxe.server.type":"Pxe Server Type", + "label.SNMP.community":"SNMP Community", + "label.SNMP.port":"SNMP Port", + "label.SR.name":"SR Name-Label", + "label.SharedMountPoint":"SharedMountPoint", + "label.TFTP.dir":"TFTP Directory", + "label.VMFS.datastore":"VMFS datastore", + "label.VMs.in.tier":"VMs in tier", + "label.VPC.limits":"VPC limits", + "label.VPC.router.details":"VPC router details", + "label.VPN.connection":"VPN Connection", + "label.VPN.customer.gateway":"VPN Customer Gateway", + "label.VPN.gateway":"VPN Gateway", + "label.Xenserver.Tools.Version61plus":"Original XS Version is 6.1+", + "label.about":"About", + "label.about.app":"About CloudStack", + "label.accept.project.invitation":"Accept project invitation", + "label.access":"Access", + "label.account":"Account", + "label.accounts":"Accounts", + "label.account.and.security.group":"Account, Security group", + "label.account.details":"Account details", + "label.account.id":"Account ID", + "label.account.lower":"account", + "label.account.name":"Account Name", + "label.account.specific":"Account-Specific", + "label.account.type":"Account Type", + "label.accounts":"Accounts", + "label.acl":"ACL", + "label.acl.id":"ACL ID", + "label.acl.export": "Export ACLs", + "label.acl.list.rules":"ACL List Rules", + "label.acl.name":"ACL Name", + "label.acl.replaced":"ACL replaced", + "label.acl.reason": "Reason", + "label.acl.reason.description": "Enter the reason behind an ACL rule.", + "label.acquire.new.ip":"Acquire New IP", + "label.acquire.new.secondary.ip":"Acquire new secondary IP", + "label.action":"Action", + "label.action.attach.disk":"Attach Disk", + "label.action.attach.disk.processing":"Attaching Disk....", + "label.action.attach.iso":"Attach ISO", + "label.action.attach.iso.processing":"Attaching ISO....", + "label.action.cancel.maintenance.mode":"Cancel Maintenance Mode", + "label.action.cancel.maintenance.mode.processing":"Cancelling Maintenance Mode....", + "label.action.change.password":"Change Password", + "label.action.change.service":"Change Service", + "label.action.change.service.processing":"Changing Service....", + "label.action.configure.samlauthorization":"Configure SAML SSO Authorization", + "label.action.copy.ISO":"Copy ISO", + "label.action.copy.ISO.processing":"Copying ISO....", + "label.action.copy.template":"Copy Template", + "label.action.copy.template.processing":"Copying Template....", + "label.action.create.template":"Create Template", + "label.action.create.template.from.vm":"Create Template from VM", + "label.action.create.template.from.volume":"Create Template from Volume", + "label.action.create.template.processing":"Creating Template....", + "label.action.create.vm":"Create VM", + "label.action.create.vm.processing":"Creating VM....", + "label.action.create.volume":"Create Volume", + "label.action.create.volume.processing":"Creating Volume....", + "label.action.delete.backup.offering":"Delete Backup Offering", + "label.action.delete.IP.range":"Delete IP Range", + "label.action.delete.IP.range.processing":"Deleting IP Range....", + "label.action.delete.ISO":"Delete ISO", + "label.action.delete.ISO.processing":"Deleting ISO....", + "label.action.delete.account":"Delete account", + "label.action.delete.account.processing":"Deleting account....", + "label.action.delete.cluster":"Delete Cluster", + "label.action.delete.cluster.processing":"Deleting Cluster....", + "label.action.delete.disk.offering":"Delete Disk Offering", + "label.action.delete.disk.offering.processing":"Deleting Disk Offering....", + "label.action.delete.domain":"Delete Domain", + "label.action.delete.domain.processing":"Deleting Domain....", + "label.action.delete.firewall":"Delete firewall rule", + "label.action.delete.firewall.processing":"Deleting Firewall....", + "label.action.delete.ingress.rule":"Delete Ingress Rule", + "label.action.delete.ingress.rule.processing":"Deleting Ingress Rule....", + "label.action.delete.load.balancer":"Delete load balancer rule", + "label.action.delete.load.balancer.processing":"Deleting Load Balancer....", + "label.action.delete.network":"Delete Network", + "label.action.delete.network.processing":"Deleting Network....", + "label.action.delete.nexusVswitch":"Delete Nexus 1000v", + "label.action.delete.nic":"Remove NIC", + "label.action.delete.physical.network":"Delete physical network", + "label.action.delete.pod":"Delete Pod", + "label.action.delete.pod.processing":"Deleting Pod....", + "label.action.delete.primary.storage":"Delete Primary Storage", + "label.action.delete.primary.storage.processing":"Deleting Primary Storage....", + "label.action.delete.secondary.storage":"Delete Secondary Storage", + "label.action.delete.secondary.storage.processing":"Deleting Secondary Storage....", + "label.action.delete.security.group":"Delete Security Group", + "label.action.delete.security.group.processing":"Deleting Security Group....", + "label.action.delete.service.offering":"Delete Service Offering", + "label.action.delete.service.offering.processing":"Deleting Service Offering....", + "label.action.delete.snapshot":"Delete Snapshot", + "label.action.delete.snapshot.processing":"Deleting Snapshot....", + "label.action.delete.system.service.offering":"Delete System Service Offering", + "label.action.delete.template":"Delete Template", + "label.action.delete.template.processing":"Deleting Template....", + "label.action.delete.user":"Delete User", + "label.action.delete.user.processing":"Deleting User....", + "label.action.delete.volume":"Delete Volume", + "label.action.delete.volume.processing":"Deleting Volume....", + "label.action.delete.zone":"Delete Zone", + "label.action.delete.zone.processing":"Deleting Zone....", + "label.action.destroy.instance":"Destroy Instance", + "label.action.destroy.instance.processing":"Destroying Instance....", + "label.action.destroy.systemvm":"Destroy System VM", + "label.action.destroy.systemvm.processing":"Destroying System VM....", + "label.action.destroy.volume":"Destroy Volume", + "label.action.detach.disk":"Detach Disk", + "label.action.detach.disk.processing":"Detaching Disk....", + "label.action.detach.iso":"Detach ISO", + "label.action.detach.iso.processing":"Detaching ISO....", + "label.action.disable.account":"Disable account", + "label.action.disable.account.processing":"Disabling account....", + "label.action.disable.cluster":"Disable Cluster", + "label.action.disable.cluster.processing":"Disabling Cluster....", + "label.action.disable.nexusVswitch":"Disable Nexus 1000v", + "label.action.disable.physical.network":"Disable physical network", + "label.action.disable.pod":"Disable Pod", + "label.action.disable.pod.processing":"Disabling Pod....", + "label.action.disable.static.NAT":"Disable Static NAT", + "label.action.disable.static.NAT.processing":"Disabling Static NAT....", + "label.action.disable.user":"Disable User", + "label.action.disable.user.processing":"Disabling User....", + "label.action.disable.zone":"Disable Zone", + "label.action.disable.zone.processing":"Disabling Zone....", + "label.action.download.ISO":"Download ISO", + "label.action.download.template":"Download Template", + "label.action.download.volume":"Download Volume", + "label.action.download.volume.processing":"Downloading Volume....", + "label.action.edit.ISO":"Edit ISO", + "label.action.edit.account":"Edit account", + "label.action.edit.disk.offering":"Edit Disk Offering", + "label.action.edit.domain":"Edit Domain", + "label.action.edit.global.setting":"Edit Global Setting", + "label.action.edit.host":"Edit Host", + "label.action.edit.instance":"Edit Instance", + "label.action.edit.network":"Edit Network", + "label.action.edit.network.offering":"Edit Network Offering", + "label.action.edit.network.processing":"Editing Network....", + "label.action.edit.pod":"Edit Pod", + "label.action.edit.primary.storage":"Edit Primary Storage", + "label.action.edit.resource.limits":"Edit Resource Limits", + "label.action.edit.service.offering":"Edit Service Offering", + "label.action.edit.template":"Edit Template", + "label.action.edit.user":"Edit User", + "label.action.edit.zone":"Edit Zone", + "label.action.enable.account":"Enable account", + "label.action.enable.account.processing":"Enabling account....", + "label.action.enable.cluster":"Enable Cluster", + "label.action.enable.cluster.processing":"Enabling Cluster....", + "label.action.enable.maintenance.mode":"Enable Maintenance Mode", + "label.action.enable.maintenance.mode.processing":"Enabling Maintenance Mode....", + "label.action.enable.nexusVswitch":"Enable Nexus 1000v", + "label.action.enable.physical.network":"Enable physical network", + "label.action.enable.pod":"Enable Pod", + "label.action.enable.pod.processing":"Enabling Pod....", + "label.action.enable.static.NAT":"Enable Static NAT", + "label.action.enable.static.NAT.processing":"Enabling Static NAT....", + "label.action.enable.user":"Enable User", + "label.action.enable.user.processing":"Enabling User....", + "label.action.enable.zone":"Enable Zone", + "label.action.enable.zone.processing":"Enabling Zone....", + "label.action.expunge.instance":"Expunge Instance", + "label.action.expunge.instance.processing":"Expunging Instance....", + "label.action.force.reconnect":"Force Reconnect", + "label.action.force.reconnect.processing":"Reconnecting....", + "label.action.generate.keys":"Generate Keys", + "label.action.generate.keys.processing":"Generate Keys....", + "label.action.get.diagnostics":"Get Diagnostics Data", + "label.action.list.nexusVswitch":"List Nexus 1000v", + "label.action.lock.account":"Lock account", + "label.action.lock.account.processing":"Locking account....", + "label.action.manage.cluster":"Manage Cluster", + "label.action.manage.cluster.processing":"Managing Cluster....", + "label.action.migrate.instance":"Migrate Instance", + "label.action.migrate.instance.processing":"Migrating Instance....", + "label.action.migrate.router":"Migrate Router", + "label.action.migrate.router.processing":"Migrating Router....", + "label.action.migrate.systemvm":"Migrate System VM", + "label.action.migrate.systemvm.processing":"Migrating System VM....", + "label.action.reboot.instance":"Reboot Instance", + "label.action.reboot.instance.processing":"Rebooting Instance....", + "label.action.reboot.router":"Reboot Router", + "label.action.reboot.router.processing":"Rebooting Router....", + "label.action.reboot.systemvm":"Reboot System VM", + "label.action.reboot.systemvm.processing":"Rebooting System VM....", + "label.action.recover.volume":"Recover Volume", + "label.action.recurring.snapshot":"Recurring Snapshots", + "label.action.register.iso":"Register ISO", + "label.action.register.ncc":"Register NCC", + "label.action.register.template":"Register Template from URL", + "label.action.release.ip":"Release IP", + "label.action.release.ip.processing":"Releasing IP....", + "label.action.remove.host":"Remove Host", + "label.action.remove.host.processing":"Removing Host....", + "label.action.reset.password":"Reset Password", + "label.action.reset.password.processing":"Resetting Password....", + "label.action.resize.volume":"Resize Volume", + "label.action.resize.volume.processing":"Resizing Volume....", + "label.action.resource.limits":"Resource limits", + "label.action.restore.instance":"Restore Instance", + "label.action.restore.instance.processing":"Restoring Instance....", + "label.action.revert.snapshot":"Revert to Snapshot", + "label.action.revert.snapshot.processing":"Reverting to Snapshot...", + "label.action.run.diagnostics":"Run Diagnostics", + "label.action.secure.host":"Provision Host Security Keys", + "label.action.start.instance":"Start Instance", + "label.action.share.iso": "Update ISO Permissions", + "label.action.share.template": "Update Template Permissions", + "label.action.start.instance.processing":"Starting Instance....", + "label.action.start.router":"Start Router", + "label.action.start.router.processing":"Starting Router....", + "label.action.start.systemvm":"Start System VM", + "label.action.start.systemvm.processing":"Starting System VM....", + "label.action.stop.instance":"Stop Instance", + "label.action.stop.instance.processing":"Stopping Instance....", + "label.action.stop.router":"Stop Router", + "label.action.stop.router.processing":"Stopping Router....", + "label.action.router.health.checks":"Get health checks result", + "label.perform.fresh.checks":"Perform fresh checks", + "label.action.stop.systemvm":"Stop System VM", + "label.action.stop.systemvm.processing":"Stopping System VM....", + "label.action.take.snapshot":"Take Snapshot", + "label.action.take.snapshot.processing":"Taking Snapshot....", + "label.action.unmanage.cluster":"Unmanage Cluster", + "label.action.unmanage.cluster.processing":"Unmanaging Cluster....", + "label.action.update.offering.access":"Update Offering Access", + "label.action.update.OS.preference":"Update OS Preference", + "label.action.update.OS.preference.processing":"Updating OS Preference....", + "label.action.update.resource.count":"Update Resource Count", + "label.action.update.resource.count.processing":"Updating Resource Count....", + "label.action.vmsnapshot.create":"Take VM Snapshot", + "label.action.vmsnapshot.delete":"Delete VM snapshot", + "label.action.vmsnapshot.revert":"Revert to VM snapshot", + "label.action.vmstoragesnapshot.create":"Take VM volume snapshot", + "label.actions":"Actions", + "label.activate.project":"Activate Project", + "label.active.sessions":"Active Sessions", + "label.add":"Add", + "label.add.ACL":"Add ACL", + "label.add.BigSwitchBcf.device":"Add BigSwitch BCF Controller", + "label.add.BrocadeVcs.device":"Add Brocade Vcs Switch", + "label.add.F5.device":"Add F5 device", + "label.add.LDAP.account":"Add LDAP Account", + "label.add.NiciraNvp.device":"Add Nvp Controller", + "label.add.OpenDaylight.device":"Add OpenDaylight Controller", + "label.add.PA.device":"Add Palo Alto device", + "label.add.SRX.device":"Add SRX device", + "label.add.VM.to.tier":"Add VM to tier", + "label.add.VPN.gateway":"Add VPN Gateway", + "label.add.account":"Add Account", + "label.add.account.to.project":"Add account to project", + "label.add.accounts":"Add accounts", + "label.add.accounts.to":"Add accounts to", + "label.add.acl.list":"Add ACL List", + "label.edit.acl.list": "Edit ACL List", + "label.add.affinity.group":"Add new affinity group", + "label.add.baremetal.dhcp.device":"Add Baremetal DHCP Device", + "label.add.baremetal.rack.configuration":"Add Baremetal Rack Configuration", + "label.add.by":"Add by", + "label.add.by.cidr":"Add By CIDR", + "label.add.by.group":"Add By Group", + "label.add.certificate":"Add Certificate", + "label.add.ciscoASA1000v":"Add CiscoASA1000v Resource", + "label.add.cluster":"Add Cluster", + "label.add.compute.offering":"Add compute offering", + "label.add.direct.iprange":"Add Direct Ip Range", + "label.add.disk.offering":"Add Disk Offering", + "label.add.domain":"Add Domain", + "label.add.egress.rule":"Add egress rule", + "label.add.firewall":"Add firewall rule", + "label.add.globo.dns":"Add GloboDNS", + "label.add.gslb":"Add GSLB", + "label.add.guest.network":"Add guest network", + "label.add.host":"Add Host", + "label.add.ingress.rule":"Add Ingress Rule", + "label.add.intermediate.certificate":"Add intermediate certificate", + "label.add.internal.lb":"Add Internal LB", + "label.add.ip.range":"Add IP Range", + "label.add.isolated.guest.network":"Add Isolated Guest Network", + "label.add.isolated.guest.network.with.sourcenat":"Add Isolated Guest Network with SourceNat", + "label.add.isolated.network":"Add Isolated Network", + "label.add.kubernetes.cluster":"Add Kubernetes Cluster", + "label.add.kubernetes.version":"Add Kubernetes Version", + "label.add.l2.guest.network":"Add L2 Guest Network", + "label.add.ldap.account":"Add LDAP account", + "label.add.list.name":"ACL List Name", + "label.add.load.balancer":"Add Load Balancer", + "label.add.management.ip.range":"Add Management IP Range", + "label.add.more":"Add More", + "label.add.netScaler.device":"Add Netscaler device", + "label.add.network":"Add Network", + "label.add.network.ACL":"Add network ACL", + "label.add.network.acl.list":"Add Network ACL List", + "label.add.network.device":"Add Network Device", + "label.add.network.offering":"Add network offering", + "label.add.new.F5":"Add new F5", + "label.add.new.iso":"Add new ISO", + "label.add.new.NetScaler":"Add new NetScaler", + "label.add.new.PA":"Add new Palo Alto", + "label.add.new.SRX":"Add new SRX", + "label.add.new.gateway":"Add new gateway", + "label.add.new.tier":"Add new tier", + "label.add.nfs.secondary.staging.store":"Add NFS Secondary Staging Store", + "label.add.physical.network":"Add physical network", + "label.add.pod":"Add Pod", + "label.add.port.forwarding.rule":"Add port forwarding rule", + "label.add.portable.ip.range":"Add Portable IP Range", + "label.add.primary.storage":"Add Primary Storage", + "label.add.private.gateway":"Add Private Gateway", + "label.add.region":"Add Region", + "label.add.resources":"Add Resources", + "label.add.role":"Add Role", + "label.add.route":"Add route", + "label.add.rule":"Add rule", + "label.add.rule.desc": "Create a new ACL rule", + "label.add.secondary.storage":"Add Secondary Storage", + "label.add.security.group":"Add Security Group", + "label.add.service.offering":"Add Service Offering", + "label.add.static.nat.rule":"Add static NAT rule", + "label.add.static.route":"Add static route", + "label.add.system.service.offering":"Add System Service Offering", + "label.add.template":"Add Template", + "label.add.to.group":"Add to group", + "label.add.ucs.manager":"Add UCS Manager", + "label.add.user":"Add User", + "label.add.userdata":"Userdata", + "label.add.vlan":"Add VLAN", + "label.add.vm":"Add VM", + "label.add.vms":"Add VMs", + "label.add.vms.to.lb":"Add VM(s) to load balancer rule", + "label.add.vmware.datacenter":"Add VMware datacenter", + "label.add.vnmc.device":"Add VNMC device", + "label.add.vnmc.provider":"Add VNMC provider", + "label.add.volume":"Add Volume", + "label.add.vpc":"Add VPC", + "label.add.vpc.offering":"Add VPC Offering", + "label.add.vpn.customer.gateway":"Add VPN Customer Gateway", + "label.add.vpn.user":"Add VPN user", + "label.add.vxlan":"Add VXLAN", + "label.add.zone":"Add Zone", + "label.added.brocade.vcs.switch":"Added new Brocade Vcs Switch", + "label.added.network.offering":"Added network offering", + "label.added.new.bigswitch.bcf.controller":"Added new BigSwitch BCF Controller", + "label.added.nicira.nvp.controller":"Added new Nicira NVP Controller", + "label.addes.new.f5":"Added new F5", + "label.adding":"Adding", + "label.adding.cluster":"Adding Cluster", + "label.adding.failed":"Adding Failed", + "label.adding.pod":"Adding Pod", + "label.adding.processing":"Adding....", + "label.adding.succeeded":"Adding Succeeded", + "label.adding.user":"Adding User", + "label.adding.zone":"Adding Zone", + "label.additional.networks":"Additional Networks", + "label.admin":"Admin", + "label.admin.accounts":"Admin Accounts", + "label.advanced":"Advanced", + "label.advanced.mode":"Advanced Mode", + "label.advanced.search":"Advanced Search", + "label.affinity":"Affinity", + "label.affinity.group":"Affinity Group", + "label.affinity.groups":"Affinity Groups", + "label.agent.password":"Agent Password", + "label.agent.port":"Agent Port", + "label.agent.state":"Agent State", + "label.agent.username":"Agent Username", + "label.agree":"Agree", + "label.alert":"Alert", + "label.alert.archived":"Alert Archived", + "label.alert.deleted":"Alert Deleted", + "label.alert.details":"Alert details", + "label.algorithm":"Algorithm", + "label.allocated":"Allocated", + "label.allocation.state":"Allocation State", + "label.allow":"Allow", + "label.all.zones":"All zones", + "label.annotated.by":"Annotator", + "label.annotation":"Annotation", + "label.anti.affinity":"Anti-affinity", + "label.anti.affinity.group":"Anti-affinity Group", + "label.anti.affinity.groups":"Anti-affinity Groups", + "label.api.key":"API Key", + "label.api.version":"API Version", + "label.app.name":"CloudStack", + "label.apply":"Apply", + "label.archive":"Archive", + "label.archive.alerts":"Archive alerts", + "label.archive.events":"Archive events", + "label.assign":"Assign", + "label.assign.instance.another":"Assign Instance to Another Account", + "label.assign.to.load.balancer":"Assigning instance to load balancer", + "label.assign.vms":"Assign VMs", + "label.assigned.vms":"Assigned VMs", + "label.associate.public.ip":"Associate Public IP", + "label.associated.network":"Associated Network", + "label.associated.network.id":"Associated Network ID", + "label.associated.profile":"Associated Profile", + "label.attached.iso":"Attached ISO", + "label.author.email":"Author e-mail", + "label.author.name":"Author name", + "label.autoscale":"AutoScale", + "label.autoscale.configuration.wizard":"AutoScale Configuration Wizard", + "label.availability":"Availability", + "label.availability.zone":"Availability Zone", + "label.availabilityZone":"availabilityZone", + "label.available":"Available", + "label.available.public.ips":"Available Public IP Addresses", + "label.back":"Back", + "label.bandwidth":"Bandwidth", + "label.baremetal.dhcp.devices":"Baremetal DHCP Devices", + "label.baremetal.dhcp.provider":"Baremetal DHCP Provider", + "label.baremetal.pxe.device":"Add Baremetal PXE Device", + "label.baremetal.pxe.devices":"Baremetal PXE Devices", + "label.baremetal.pxe.provider":"Baremetal PXE Provider", + "label.baremetal.rack.configuration":"Baremetal Rack Configuration", + "label.basic":"Basic", + "label.basic.mode":"Basic Mode", + "label.bigswitch.bcf.details":"BigSwitch BCF details", + "label.bigswitch.bcf.nat":"BigSwitch BCF NAT Enabled", + "label.bigswitch.controller.address":"BigSwitch BCF Controller Address", + "label.blade.id":"Blade ID", + "label.blades":"Blades", + "label.bootable":"Bootable", + "label.broadcast.domain.range":"Broadcast domain range", + "label.broadcast.domain.type":"Broadcast Domain Type", + "label.broadcast.uri":"Broadcast URI", + "label.broadcasturi":"broadcasturi", + "label.broadcat.uri":"Broadcast URI", + "label.brocade.vcs.address":"Vcs Switch Address", + "label.brocade.vcs.details":"Brocade Vcs Switch details", + "label.by.account":"By Account", + "label.by.alert.type":"By alert type", + "label.by.availability":"By Availability", + "label.by.date.end":"By date (end)", + "label.by.date.start":"By date (start)", + "label.by.domain":"By Domain", + "label.by.end.date":"By End Date", + "label.by.event.type":"By event type", + "label.by.level":"By Level", + "label.by.pod":"By Pod", + "label.by.role":"By Role", + "label.by.start.date":"By Start Date", + "label.by.state":"By State", + "label.by.traffic.type":"By Traffic Type", + "label.by.type":"By Type", + "label.by.type.id":"By Type ID", + "label.by.zone":"By Zone", + "label.bypass.vlan.overlap.check": "Bypass VLAN id/range overlap", + "label.bytes.received":"Bytes Received", + "label.bytes.sent":"Bytes Sent", + "label.cache.mode":"Write-cache Type", + "label.cancel":"Cancel", + "label.capacity":"Capacity", + "label.capacity.bytes":"Capacity Bytes", + "label.capacity.iops":"Capacity IOPS", + "label.certificate":"Server certificate", + "label.certificate.details":"Certificate Details", + "label.certificate.name":"Certificate", + "label.certificateid":"Certificate ID", + "label.chain":"Chain", + "label.change.affinity":"Change Affinity", + "label.change.ipaddress":"Change IP address for NIC", + "label.change.service.offering":"Change service offering", + "label.change.value":"Change value", + "label.character":"Character", + "label.chassis":"Chassis", + "label.checksum":"checksum", + "label.cidr":"CIDR", + "label.cidr.account":"CIDR or Account/Security Group", + "label.cidr.list":"Source CIDR", + "label.cidr.destination.list":"Destination CIDR", + "label.cisco.nexus1000v.ip.address":"Nexus 1000v IP Address", + "label.cisco.nexus1000v.password":"Nexus 1000v Password", + "label.cisco.nexus1000v.username":"Nexus 1000v Username", + "label.ciscovnmc.resource.details":"CiscoVNMC resource details", + "label.clean.up":"Clean up", + "label.clear.list":"Clear list", + "label.close":"Close", + "label.cloud.console":"Cloud Management Console", + "label.cloud.managed":"Cloud.com Managed", + "label.cluster":"Cluster", + "label.cluster.name":"Cluster Name", + "label.cluster.size":"Cluster size", + "label.cluster.size.worker.nodes":"Cluster size (Worker nodes)", + "label.cluster.type":"Cluster Type", + "label.clusters":"Clusters", + "label.clvm":"CLVM", + "label.code":"Code", + "label.community":"Community", + "label.compute":"Compute", + "label.compute.and.storage":"Compute and Storage", + "label.compute.offering":"Compute offering", + "label.compute.offering.access":"Compute offering access", + "label.compute.offering.type":"Compute offering type", + "label.compute.offering.custom.constrained":"Custom Constrained", + "label.compute.offering.custom.unconstrained":"Custom Unconstrained", + "label.compute.offering.fixed":"Fixed Offering", + "label.compute.offerings":"Compute Offerings", + "label.configuration":"Configuration", + "label.configure":"Configure", + "label.configure.ldap":"Configure LDAP", + "label.configure.network.ACLs":"Configure Network ACLs", + "label.configure.sticky.policy":"Configure Sticky Policy", + "label.configure.vpc":"Configure VPC", + "label.confirm.password":"Confirm password", + "label.confirmation":"Confirmation", + "label.congratulations":"Congratulations!", + "label.conserve.mode":"Conserve mode", + "label.console.proxy":"Console proxy", + "label.console.proxy.vm":"Console Proxy VM", + "label.continue":"Continue", + "label.continue.basic.install":"Continue with basic installation", + "label.copying.iso":"Copying ISO", + "label.copy.text": "Copy Text", + "label.corrections.saved":"Corrections saved", + "label.counter":"Counter", + "label.cpu":"CPU", + "label.cpu.allocated":"CPU Allocated", + "label.cpu.allocated.for.VMs":"CPU Allocated for VMs", + "label.cpu.limits":"CPU limits", + "label.cpu.mhz":"CPU (in MHz)", + "label.cpu.utilized":"CPU Utilized", + "label.create.backup":"Start Backup", + "label.create.VPN.connection":"Create VPN Connection", + "label.create.nfs.secondary.staging.storage":"Create NFS Secondary Staging Store", + "label.create.nfs.secondary.staging.store":"Create NFS secondary staging store", + "label.create.project":"Create project", + "label.create.ssh.key.pair":"Create a SSH Key Pair", + "label.create.template":"Create template", + "label.created":"Created", + "label.created.by.system":"Created by system", + "label.cross.zones":"Cross Zones", + "label.custom":"Custom", + "label.custom.disk.iops":"Custom IOPS", + "label.custom.disk.offering":"Custom Disk Offering", + "label.custom.disk.size":"Custom Disk Size", + "label.daily":"Daily", + "label.data.disk.offering":"Data Disk Offering", + "label.date":"Date", + "label.day":"Day", + "label.day.of.month":"Day of Month", + "label.day.of.week":"Day of Week", + "label.dashboard.endpoint":"Dashboard endpoint", + "label.dc.name":"DC Name", + "label.dead.peer.detection":"Dead Peer Detection", + "label.decline.invitation":"Decline invitation", + "label.dedicate":"Dedicate", + "label.dedicate.cluster":"Dedicate Cluster", + "label.dedicate.host":"Dedicate Host", + "label.dedicate.pod":"Dedicate Pod", + "label.dedicate.vlan.vni.range":"Dedicate VLAN/VNI Range", + "label.dedicate.zone":"Dedicate Zone", + "label.dedicated":"Dedicated", + "label.dedicated.vlan.vni.ranges":"Dedicated VLAN/VNI Ranges", + "label.default":"Default", + "label.default.egress.policy":"Default egress policy", + "label.default.use":"Default Use", + "label.default.view":"Default View", + "label.delete":"Delete", + "label.delete.BigSwitchBcf":"Remove BigSwitch BCF Controller", + "label.delete.BrocadeVcs":"Remove Brocade Vcs Switch", + "label.delete.F5":"Delete F5", + "label.delete.NetScaler":"Delete NetScaler", + "label.delete.NiciraNvp":"Remove Nvp Controller", + "label.delete.OpenDaylight.device":"Delete OpenDaylight Controller", + "label.delete.PA":"Delete Palo Alto", + "label.delete.SRX":"Delete SRX", + "label.delete.VPN.connection":"Delete VPN connection", + "label.delete.VPN.customer.gateway":"Delete VPN Customer Gateway", + "label.delete.VPN.gateway":"Delete VPN Gateway", + "label.delete.acl.list":"Delete ACL List", + "label.delete.affinity.group":"Delete Affinity Group", + "label.delete.alerts":"Delete alerts", + "label.delete.baremetal.rack.configuration":"Delete Baremetal Rack Configuration", + "label.delete.ciscoASA1000v":"Delete CiscoASA1000v", + "label.delete.ciscovnmc.resource":"Delete CiscoVNMC resource", + "label.delete.events":"Delete events", + "label.delete.gateway":"Delete gateway", + "label.delete.internal.lb":"Delete Internal LB", + "label.delete.iso":"Delete ISO", + "label.delete.kubernetes.version":"Delete Kubernetes version", + "label.delete.portable.ip.range":"Delete Portable IP Range", + "label.delete.profile":"Delete Profile", + "label.delete.project":"Delete project", + "label.delete.role":"Delete Role", + "label.delete.secondary.staging.store":"Delete Secondary Staging Store", + "label.delete.sslcertificate":"Delete SSL Certificate", + "label.delete.ucs.manager":"Delete UCS Manager", + "label.delete.volumes":"Data Volumes to be deleted", + "label.delete.vpn.user":"Delete VPN user", + "label.deleting.failed":"Deleting Failed", + "label.deleting.processing":"Deleting....", + "label.deny":"Deny", + "label.deployment.planner":"Deployment planner", + "label.description":"Description", + "label.destination.physical.network.id":"Destination physical network ID", + "label.destination.zone":"Destination Zone", + "label.destroy":"Destroy", + "label.destroy.kubernetes.cluster":"Destroy Kubernetes cluster", + "label.destroy.router":"Destroy router", + "label.destroy.vm.graceperiod":"Destroy VM Grace Period", + "label.detaching.disk":"Detaching Disk", + "label.details":"Details", + "label.device.id":"Device ID", + "label.devices":"Devices", + "label.dhcp":"DHCP", + "label.direct.attached.public.ip":"Direct Attached Public IP", + "label.direct.download":"Direct Download", + "label.direct.ips":"Shared Network IPs", + "label.disable.autoscale":"Disable Autoscale", + "label.disable.host":"Disable Host", + "label.disable.network.offering":"Disable network offering", + "label.disable.provider":"Disable provider", + "label.disable.vnmc.provider":"Disable VNMC provider", + "label.disable.vpc.offering":"Disable VPC offering", + "label.disable.vpn":"Disable Remote Access VPN", + "label.disabled":"Disabled", + "label.disabling.vpn.access":"Disabling VPN Access", + "label.disassociate.profile.blade":"Disassociate Profile from Blade", + "label.disbale.vnmc.device":"Disable VNMC device", + "label.disk.allocated":"Disk Allocated", + "label.disk.bytes.read.rate":"Disk Read Rate (BPS)", + "label.disk.bytes.write.rate":"Disk Write Rate (BPS)", + "label.disk.iops.max":"Max IOPS", + "label.disk.iops.min":"Min IOPS", + "label.disk.iops.read.rate":"Disk Read Rate (IOPS)", + "label.disk.iops.total":"IOPS Total", + "label.disk.iops.allocated":"IOPS Allocated", + "label.disk.iops.write.rate":"Disk Write Rate (IOPS)", + "label.disk.offering":"Disk Offering", + "label.disk.offering.access":"Disk offering access", + "label.disk.offering.details":"Disk offering details", + "label.disk.newOffering": "New Disk Offering", + "label.disk.newOffering.description": "New disk offering to be used by this volume after the migration.", + "label.disk.physicalsize":"Physical Size", + "label.disk.provisioningtype":"Provisioning Type", + "label.disk.read.bytes":"Disk Read (Bytes)", + "label.disk.read.io":"Disk Read (IO)", + "label.disk.size":"Disk Size", + "label.disk.size.gb":"Disk Size (in GB)", + "label.disk.total":"Disk Total", + "label.disk.utilisation":"Utilisation", + "label.disk.virtualsize":"Virtual Size", + "label.disk.volume":"Disk Volume", + "label.disk.write.bytes":"Disk Write (Bytes)", + "label.disk.write.io":"Disk Write (IO)", + "label.diskoffering":"diskoffering", + "label.display.name":"Display Name", + "label.display.text":"Display Text", + "label.distributedrouter":"Distributed Router", + "label.dns":"DNS", + "label.dns.1":"DNS 1", + "label.dns.2":"DNS 2", + "label.domain":"Domain", + "label.domains":"Domains", + "label.domain.admin":"Domain Admin", + "label.domain.details":"Domain details", + "label.domain.id":"Domain ID", + "label.domain.lower":"domain", + "label.domain.name":"Domain Name", + "label.domain.router":"Domain router", + "label.domain.suffix":"DNS Domain Suffix (i.e., xyz.com)", + "label.done":"Done", + "label.double.quotes.are.not.allowed":"Double quotes are not allowed", + "label.download.kubernetes.cluster.config":"Download Kubernetes cluster config", + "label.download.progress":"Download Progress", + "label.drag.new.position":"Drag to new position", + "label.duration.in.sec":"Duration (in sec)", + "label.dynamically.scalable":"Dynamically Scalable", + "label.edit":"Edit", + "label.edit.acl.rule":"Edit ACL rule", + "label.edit.affinity.group":"Edit Affinity Group", + "label.edit.lb.rule":"Edit LB rule", + "label.edit.network.details":"Edit network details", + "label.edit.project.details":"Edit project details", + "label.edit.region":"Edit Region", + "label.edit.role":"Edit Role", + "label.edit.rule":"Edit rule", + "label.edit.secondary.ips":"Edit secondary IPs", + "label.edit.tags":"Edit tags", + "label.edit.traffic.type":"Edit traffic type", + "label.edit.vpc":"Edit VPC", + "label.egress.default.policy":"Egress Default Policy", + "label.egress.rule":"Egress rule", + "label.egress.rules":"Egress rules", + "label.elastic":"Elastic", + "label.elastic.IP":"Elastic IP", + "label.elastic.LB":"Elastic LB", + "label.email":"Email", + "label.email.lower":"email", + "label.enable.autoscale":"Enable Autoscale", + "label.enable.host":"Enable Host", + "label.enable.network.offering":"Enable network offering", + "label.enable.provider":"Enable provider", + "label.enable.s3":"Enable S3-backed Secondary Storage", + "label.enable.swift":"Enable Swift", + "label.enable.vnmc.device":"Enable VNMC device", + "label.enable.vnmc.provider":"Enable VNMC provider", + "label.enable.vpc.offering":"Enable VPC offering", + "label.enable.vpn":"Enable Remote Access VPN", + "label.enabling.vpn":"Enabling VPN", + "label.enabling.vpn.access":"Enabling VPN Access", + "label.end.IP":"End IP", + "label.end.port":"End Port", + "label.end.reserved.system.IP":"End Reserved system IP", + "label.end.vlan":"End VLAN", + "label.end.vxlan":"End VXLAN", + "label.endpoint":"Endpoint", + "label.endpoint.or.operation":"Endpoint or Operation", + "label.enter.hardware.setup":"Enter the hardware setup menu", + "label.enter.token":"Enter token", + "label.error":"Error", + "label.error.code":"Error Code", + "label.error.upper":"ERROR", + "label.esx.host":"ESX/ESXi Host", + "label.event":"Event", + "label.event.archived":"Event Archived", + "label.event.deleted":"Event Deleted", + "label.event.timeline":"Event Timeline", + "label.every":"Every", + "label.example":"Example", + "label.expunge":"Expunge", + "label.external.id":"External ID", + "label.external.link":"External link", + 'label.external.loadbalancer.ip.address': "External load balancer IP address", + "label.extractable":"Extractable", + "label.extractable.lower":"extractable", + "label.f5":"F5", + "label.f5.details":"F5 details", + "label.failed":"Failed", + "label.featured":"Featured", + "label.fetch.latest":"Fetch latest", + "label.filterBy":"Filter by", + "label.fingerprint":"FingerPrint", + "label.firewall":"Firewall", + "label.first.name":"First Name", + "label.firstname.lower":"firstname", + "label.forged.transmits":"Forged Transmits", + "label.format":"Format", + "label.format.lower":"format", + "label.friday":"Friday", + "label.french.azerty.keyboard":"French AZERTY keyboard", + "label.full":"Full", + "label.full.path":"Full path", + "label.gateway":"Gateway", + "label.general.alerts":"General Alerts", + "label.generating.url":"Generating URL", + "label.get.diagnostics.desc":"If you wish to override the standard files returned, enter them here. Otherwise leave blank and press OK", + "label.get.diagnostics.files":"Alternate Files to Retrieve", + "label.globo.dns":"GloboDNS", + "label.globo.dns.configuration":"GloboDNS Configuration", + "label.gluster.volume":"Volume", + "label.go.step.2":"Go to Step 2", + "label.go.step.3":"Go to Step 3", + "label.go.step.4":"Go to Step 4", + "label.go.step.5":"Go to Step 5", + "label.gpu":"GPU", + "label.group":"Group", + "label.group.by.account":"Group by account", + "label.group.by.cluster":"Group by cluster", + "label.group.by.pod":"Group by pod", + "label.group.by.zone":"Group by zone", + "label.group.optional":"Group (Optional)", + "label.gslb":"GSLB", + "label.gslb.assigned.lb":"Assigned load balancing", + "label.gslb.assigned.lb.more":"Assign more load balancing", + "label.gslb.delete":"Delete GSLB", + "label.gslb.details":"GSLB details", + "label.gslb.domain.name":"GSLB Domain Name", + "label.gslb.lb.details":"Load balancing details", + "label.gslb.lb.remove":"Remove load balancing from this GSLB", + "label.gslb.lb.rule":"Load balancing rule", + "label.gslb.service":"GSLB service", + "label.gslb.service.private.ip":"GSLB service Private IP", + "label.gslb.service.public.ip":"GSLB service Public IP", + "label.gslb.servicetype":"Service Type", + "label.guest":"Guest", + "label.guest.cidr":"Guest CIDR", + "label.guest.end.ip":"Guest end IP", + "label.guest.externalId":"External Id", + "label.guest.gateway":"Guest Gateway", + "label.guest.ip":"Guest IP Address", + "label.guest.ip.range":"Guest IP Range", + "label.guest.netmask":"Guest Netmask", + "label.guest.network.details":"Guest network details", + "label.guest.networks":"Guest networks", + "label.guest.start.ip":"Guest start IP", + "label.guest.traffic":"Guest Traffic", + "label.guest.traffic.vswitch.name":"Guest Traffic vSwitch Name", + "label.guest.traffic.vswitch.type":"Guest Traffic vSwitch Type", + "label.guest.type":"Guest Type", + "label.ha.enabled":"HA Enabled", + "label.ha.configure":"Configure HA", + "label.ha.disable":"Disable HA", + "label.ha.enable":"Enable HA", + "label.ha.provider":"HA Provider", + "label.ha.state":"HA State", + "label.ha":"HA", + "label.health.check":"Health Check", + "label.health.check.advanced.options":"Advanced Options:", + "label.health.check.configurations.options":"Configuration Options:", + "label.health.check.interval.in.sec":"Health Check Interval (in sec)", + "label.health.check.message.desc":"Your load balancer will automatically perform health checks on your cloudstack instances and only route traffic to instances that pass the health check", + "label.health.check.wizard":"Health Check Wizard", + "label.healthy.threshold":"Healthy Threshold", + "label.help":"Help", + "label.hide.ingress.rule":"Hide Ingress Rule", + "label.hints":"Hints", + "label.home":"Home", + "label.host":"Host", + "label.host.MAC":"Host MAC", + "label.host.alerts":"Hosts in Alert State", + "label.host.name":"Host Name", + "label.host.tag":"Host Tag", + "label.host.tags":"Host Tags", + "label.host.ueficapability":"UEFI Supported", + "label.hosts":"Hosts", + "label.hourly":"Hourly", + "label.hvm":"HVM", + "label.hyperv.traffic.label":"HyperV Traffic Label", + "label.hypervisor":"Hypervisor", + "label.hypervisor.capabilities":"Hypervisor capabilities", + "label.hypervisor.snapshot.reserve":"Hypervisor Snapshot Reserve", + "label.hypervisor.type":"Hypervisor Type", + "label.hypervisor.version":"Hypervisor version", + "label.hypervisors":"Hypervisors", + "label.id":"ID", + "label.info":"Info", + "label.info.upper":"INFO", + "label.ingress.rule":"Ingress Rule", + "label.initiated.by":"Initiated By", + "label.inside.port.profile":"Inside Port Profile", + "label.installWizard.addClusterIntro.subtitle":"What is a cluster?", + "label.installWizard.addClusterIntro.title":"Let’s add a cluster", + "label.installWizard.addHostIntro.subtitle":"What is a host?", + "label.installWizard.addHostIntro.title":"Let’s add a host", + "label.installWizard.addPodIntro.subtitle":"What is a pod?", + "label.installWizard.addPodIntro.title":"Let’s add a pod", + "label.installWizard.addPrimaryStorageIntro.subtitle":"What is primary storage?", + "label.installWizard.addPrimaryStorageIntro.title":"Let’s add primary storage", + "label.installWizard.addSecondaryStorageIntro.subtitle":"What is secondary storage?", + "label.installWizard.addSecondaryStorageIntro.title":"Let’s add secondary storage", + "label.installWizard.addZone.title":"Add zone", + "label.installWizard.addZoneIntro.subtitle":"What is a zone?", + "label.installWizard.addZoneIntro.title":"Let’s add a zone", + "label.installWizard.click.launch":"Click the launch button.", + "label.installWizard.subtitle":"This tour will aid you in setting up your CloudStack™ installation", + "label.installWizard.title":"Hello and Welcome to CloudStack™", + "label.instance":"Instance", + "label.instance.limits":"Instance Limits", + "label.instance.name":"Instance Name", + "label.instance.port":"Instance Port", + "label.instance.scaled.up":"Instance scaled to the requested offering", + "label.instances":"Instances", + "label.instanciate.template.associate.profile.blade":"Instanciate Template and Associate Profile to Blade", + "label.intermediate.certificate":"Intermediate certificate {0}", + "label.internal.dns.1":"Internal DNS 1", + "label.internal.dns.2":"Internal DNS 2", + "label.internal.lb":"Internal LB", + "label.internal.lb.details":"Internal LB details", + "label.internal.name":"Internal name", + "label.internallbvm":"InternalLbVm", + "label.interval.type":"Interval Type", + "label.introduction.to.cloudstack":"Introduction to CloudStack™", + "label.invalid.integer":"Invalid Integer", + "label.invalid.number":"Invalid Number", + "label.invitations":"Invitations", + "label.invite":"Invite", + "label.invite.to":"Invite to", + "label.invited.accounts":"Invited accounts", + "label.ip":"IP", + "label.ip.address":"IP Address", + "label.ip.allocations":"IP Allocations", + "label.ip.limits":"Public IP Limits", + "label.ip.or.fqdn":"IP or FQDN", + "label.ip.range":"IP Range", + "label.ip.ranges":"IP Ranges", + "label.ipaddress":"IP Address", + "label.ips":"IPs", + "label.ipv4.cidr":"IPv4 CIDR", + "label.ipv4.dns1":"IPv4 DNS1", + "label.ipv4.dns2":"IPv4 DNS2", + "label.ipv4.end.ip":"IPv4 End IP", + "label.ipv4.gateway":"IPv4 Gateway", + "label.ipv4.netmask":"IPv4 Netmask", + "label.ipv4.start.ip":"IPv4 Start IP", + "label.ipv6.CIDR":"IPv6 CIDR", + "label.ipv6.address":"IPv6 IP Address", + "label.ipv6.dns1":"IPv6 DNS1", + "label.ipv6.dns2":"IPv6 DNS2", + "label.ipv6.end.ip":"IPv6 End IP", + "label.ipv6.gateway":"IPv6 Gateway", + "label.ipv6.start.ip":"IPv6 Start IP", + "label.is.default":"Is Default", + "label.is.redundant.router":"Redundant", + "label.is.shared":"Is Shared", + "label.is.system":"Is System", + "label.iscsi":"iSCSI", + "label.iso":"ISO", + "label.iso.boot":"ISO Boot", + "label.iso.id":"ISO ID", + "label.iso.name":"ISO name", + "label.iso.state":"ISO state", + "label.isolated.networks":"Isolated networks", + "label.isolation.method":"Isolation method", + "label.isolation.mode":"Isolation Mode", + "label.isolation.uri":"Isolation URI", + "label.item.listing":"Item listing", + "label.japanese.keyboard":"Japanese keyboard", + "label.keep":"Keep", + "label.keep.colon":"Keep:", + "label.key":"Key", + "label.keyboard.language":"Keyboard language", + "label.vm.boottype":"Boot Type", + "label.vm.bootmode":"Boot Mode", + "label.vm.enterhardwaresetup":"Enter hardware setup after boot", + "label.keyboard.type":"Keyboard type", + "label.kubernetes.cluster":"Kubernetes cluster", + "label.kubernetes.cluster.details":"Kubernetes cluster details", + "label.kubernetes.service":"Kubernetes Service", + "label.kubernetes.version":"Kubernetes version", + "label.kubernetes.version.details":"Kubernetes version details", + "label.kvm.traffic.label":"KVM traffic label", + "label.label":"Label", + "label.lang.arabic":"Arabic", + "label.lang.brportugese":"Brazilian Portugese", + "label.lang.catalan":"Catalan", + "label.lang.chinese":"Chinese (Simplified)", + "label.lang.dutch":"Dutch (Netherlands)", + "label.lang.english":"English", + "label.lang.french":"French", + "label.lang.german":"German", + "label.lang.hungarian":"Hungarian", + "label.lang.italian":"Italian", + "label.lang.japanese":"Japanese", + "label.lang.korean":"Korean", + "label.lang.norwegian":"Norwegian", + "label.lang.polish":"Polish", + "label.lang.russian":"Russian", + "label.lang.spanish":"Spanish", + "label.last.annotated":"Last annotation date", + "label.last.disconnected":"Last Disconnected", + "label.last.name":"Last Name", + "label.lastname.lower":"lastname", + "label.latest.events":"Latest events", + "label.launch":"Launch", + "label.launch.vm":"Launch VM", + "label.launch.zone":"Launch zone", + "label.lb.algorithm.leastconn":"Least connections", + "label.lb.algorithm.roundrobin":"Round-robin", + "label.lb.algorithm.source":"Source", + "label.lb.protocol.http":"HTTP", + "label.lb.protocol.ssl":"SSL", + "label.lb.protocol.tcp":"TCP", + "label.lb.protocol.tcp.proxy":"TCP-proxy", + "label.lb.protocol.udp":"UDP", + "label.ldap.configuration":"LDAP Configuration", + "label.ldap.group.name":"LDAP Group", + "label.ldap.link.type":"Type", + "label.ldap.port":"LDAP port", + "label.level":"Level", + "label.link.domain.to.ldap":"Link Domain to LDAP", + "label.linklocal.ip":"Link Local IP Address", + "label.load.balancer":"Load Balancer", + "label.load.balancer.type":"Load Balancer Type", + "label.load.balancing":"Load Balancing", + "label.load.balancing.policies":"Load balancing policies", + "label.loading":"Loading", + "label.local":"Local", + "label.local.file":"Local file", + "label.local.storage":"Local Storage", + "label.local.storage.enabled":"Enable local storage for User VMs", + "label.local.storage.enabled.system.vms":"Enable local storage for System VMs", + "label.login":"Login", + "label.logout":"Logout", + "label.lun":"LUN", + "label.lxc.traffic.label":"LXC Traffic Label", + "label.make.project.owner":"Make account project owner", + "label.make.redundant":"Make redundant", + "label.manage":"Manage", + "label.manage.resources":"Manage Resources", + "label.managed":"Managed", + "label.managed.state":"Managed State", + "label.management":"Management", + "label.management.ips":"Management IP Addresses", + "label.management.server":"Management Server", + "label.mac.address": "MAC Address", + "label.management.servers":"Management Servers", + "label.mac.address.changes":"MAC Address Changes", + "label.master.nodes":"Master nodes", + "label.max.cpus":"Max. CPU cores", + "label.max.guest.limit":"Max guest limit", + "label.max.instances":"Max Instances", + "label.max.memory":"Max. memory (MiB)", + "label.max.networks":"Max. networks", + "label.max.primary.storage":"Max. primary (GiB)", + "label.max.public.ips":"Max. public IPs", + "label.max.secondary.storage":"Max. secondary (GiB)", + "label.max.snapshots":"Max. snapshots", + "label.max.templates":"Max. templates", + "label.max.vms":"Max. user VMs", + "label.max.volumes":"Max. volumes", + "label.max.vpcs":"Max. VPCs", + "label.maximum":"Maximum", + "label.may.continue":"You may now continue.", + "label.md5.checksum":"MD5 checksum", + "label.memory":"Memory", + "label.memory.allocated":"Memory Allocated", + "label.memory.limits":"Memory limits (MiB)", + "label.memory.mb":"Memory (in MB)", + "label.memory.minimum.mb":"Min Memory (in MB)", + "label.memory.maximum.mb":"Max Memory (in MB)", + "label.memory.total":"Memory Total", + "label.memory.used":"Memory Used", + "label.menu.accounts":"Accounts", + "label.menu.alerts":"Alerts", + "label.menu.all.accounts":"All Accounts", + "label.menu.all.instances":"All Instances", + "label.menu.backup":"Backup", + "label.menu.backup.offerings":"Backup Offerings", + "label.menu.community.isos":"Community ISOs", + "label.menu.community.templates":"Community Templates", + "label.menu.configuration":"Configuration", + "label.menu.dashboard":"Dashboard", + "label.menu.destroyed.instances":"Destroyed Instances", + "label.menu.disk.offerings":"Disk Offerings", + "label.menu.domains":"Domains", + "label.menu.events":"Events", + "label.menu.featured.isos":"Featured ISOs", + "label.menu.featured.templates":"Featured Templates", + "label.menu.global.settings":"Global Settings", + "label.menu.infrastructure":"Infrastructure", + "label.menu.instances":"Instances", + "label.menu.ipaddresses":"IP Addresses", + "label.menu.isos":"ISOs", + "label.menu.my.accounts":"My Accounts", + "label.menu.my.instances":"My Instances", + "label.menu.my.isos":"My ISOs", + "label.menu.my.templates":"My Templates", + "label.menu.network":"Network", + "label.menu.network.offerings":"Network Offerings", + "label.menu.physical.resources":"Physical Resources", + "label.menu.regions":"Regions", + "label.menu.running.instances":"Running Instances", + "label.menu.security.groups":"Security Groups", + "label.menu.service.offerings":"Service Offerings", + "label.menu.snapshots":"Snapshots", + "label.menu.sshkeypair":"SSH KeyPair", + "label.menu.stopped.instances":"Stopped Instances", + "label.menu.storage":"Storage", + "label.menu.system":"System", + "label.menu.system.service.offerings":"System Offerings", + "label.menu.system.vms":"System VMs", + "label.menu.templates":"Templates", + "label.menu.virtual.appliances":"Virtual Appliances", + "label.menu.virtual.resources":"Virtual Resources", + "label.menu.volumes":"Volumes", + "label.menu.vpc.offerings":"VPC Offerings", + "label.metrics":"Metrics", + "label.metrics.allocated":"Allocated", + "label.metrics.clusters":"Clusters", + "label.metrics.cpu.allocated":"CPU Allocation", + "label.metrics.cpu.max.dev":"Deviation", + "label.metrics.cpu.total":"Total", + "label.metrics.cpu.usage":"CPU Usage", + "label.metrics.cpu.used.avg":"Used", + "label.metrics.disk":"Disk", + "label.metrics.disk.allocated":"Allocated", + "label.metrics.disk.iops.total":"IOPS", + "label.metrics.disk.read":"Read", + "label.metrics.disk.size":"Size", + "label.metrics.disk.storagetype":"Type", + "label.metrics.disk.total":"Total", + "label.metrics.disk.unallocated":"Unallocated", + "label.metrics.disk.usage":"Disk Usage", + "label.metrics.disk.used":"Used", + "label.metrics.disk.write":"Write", + "label.metrics.hosts":"Hosts", + "label.metrics.memory.allocated":"Mem Allocation", + "label.metrics.memory.max.dev":"Deviation", + "label.metrics.memory.total":"Total", + "label.metrics.memory.usage":"Mem Usage", + "label.metrics.memory.used.avg":"Used", + "label.metrics.name":"Name", + "label.metrics.network.read":"Read", + "label.metrics.network.usage":"Network Usage", + "label.metrics.network.write":"Write", + "label.metrics.num.cpu.cores":"Cores", + "label.metrics.outofbandmanagementpowerstate":"Power State", + "label.metrics.property":"Property", + "label.metrics.scope":"Scope", + "label.metrics.state":"State", + "label.metrics.storagepool":"Storage Pool", + "label.metrics.vm.name":"VM Name", + "label.migrate.instance.to":"Migrate instance to", + "label.migrate.instance.to.host":"Migrate instance to another host", + "label.migrate.instance.to.ps":"Migrate instance to another primary storage", + "label.migrate.lb.vm":"Migrate LB VM", + "label.migrate.router.to":"Migrate Router to", + "label.migrate.systemvm.to":"Migrate System VM to", + "label.migrate.to.host":"Migrate to host", + "label.migrate.to.storage":"Migrate to storage", + "label.migrate.volume":"Migrate Volume", + "label.migrate.volume.to.primary.storage":"Migrate volume to another primary storage", + "label.migrate.volume.newDiskOffering": "Replace disk offering?", + "label.migrate.volume.newDiskOffering.desc": "This option allows administrators to replace the old disk offering, using one that better suits the new placement of the volume.", + "label.min.instances":"Min Instances", + "label.min.past.the.hr":"min past the hr", + "label.minimum":"Minimum", + "label.minute.past.hour":"minute(s) past the hour", + "label.minutes.past.hour":"minutes(s) past the hour", + "label.mode":"Mode", + "label.monday":"Monday", + "label.monthly":"Monthly", + "label.more.templates":"More Templates", + "label.move.down.row":"Move down one row", + "label.move.to.bottom":"Move to bottom", + "label.move.to.top":"Move to top", + "label.move.up.row":"Move up one row", + "label.my.account":"My Account", + "label.my.network":"My network", + "label.my.templates":"My templates", + "label.na":"N/A", + "label.name":"Name", + "label.name.lower":"name", + "label.name.optional":"Name (Optional)", + "label.nat.port.range":"NAT Port Range", + "label.ncc":"NCC", + "label.ncc.delete":"Delete NCC", + "label.ncc.details":"NCC Details", + "label.netScaler":"NetScaler", + "label.netmask":"Netmask", + "label.netscaler.details":"NetScaler details", + "label.netscaler.service.packages":"Netscaler Service Packages", + "label.netscaler.service.packages.description":"Service Package Description", + "label.network":"Network", + "label.network.ACL":"Network ACL", + "label.network.ACL.total":"Network ACL Total", + "label.network.ACLs":"Network ACLs", + "label.network.addVM":"Add network to VM", + "label.network.cidr":"Network CIDR", + "label.network.desc":"Network Desc", + "label.network.details":"Network Details", + "label.network.device":"Network Device", + "label.network.device.type":"Network Device Type", + "label.network.domain":"Network Domain", + "label.network.domain.text":"Network domain", + "label.network.hideipaddressusage":"Hide IP Address Usage", + "label.network.id":"Network ID", + "label.network.label.display.for.blank.value":"Use default gateway", + "label.network.limits":"Network limits", + "label.network.name":"Network Name", + "label.network.offering":"Network Offering", + "label.network.offering.access":"Network offering access", + "label.network.offering.details":"Network offering details", + "label.network.offering.display.text":"Network Offering Display Text", + "label.network.offering.id":"Network Offering ID", + "label.network.offering.name":"Network Offering Name", + "label.network.rate":"Network Rate (Mb/s)", + "label.network.rate.megabytes":"Network Rate (MB/s)", + "label.network.read":"Network Read", + "label.network.service.providers":"Network Service Providers", + "label.network.type":"Network Type", + "label.network.write":"Network Write", + "label.networking.and.security":"Networking and security", + "label.networks":"Networks", + "label.new":"New", + "label.new.password":"New Password", + "label.current.password": "Current Password", + "label.new.project":"New Project", + "label.new.ssh.key.pair":"New SSH Key Pair", + "label.new.vm":"New VM", + "label.next":"Next", + "label.nexusVswitch":"Nexus 1000v", + "label.nfs":"NFS", + "label.nfs.server":"NFS Server", + "label.nfs.storage":"NFS Storage", + "label.nic.adapter.type":"NIC adapter type", + "label.nicira.controller.address":"Controller Address", + "label.nicira.l2gatewayserviceuuid":"L2 Gateway Service Uuid", + "label.nicira.l3gatewayserviceuuid":"L3 Gateway Service Uuid", + "label.nicira.nvp.details":"Nicira NVP details", + "label.nicira.transportzoneuuid":"Transport Zone Uuid", + "label.nics":"NICs", + "label.no":"No", + "label.no.actions":"No Available Actions", + "label.no.alerts":"No Recent Alerts", + "label.no.data":"No data to show", + "label.no.errors":"No Recent Errors", + "label.no.grouping":"(no grouping)", + "label.no.isos":"No available ISOs", + "label.no.items":"No Available Items", + "label.no.security.groups":"No Available Security Groups", + "label.no.thanks":"No thanks", + "label.node.root.disk.size.gb":"Node root disk size (in GB)", + "label.none":"None", + "label.not.found":"Not Found", + "label.notifications":"Notifications", + "label.num.cpu.cores":"# of CPU Cores", + "label.min.cpu.cores":"Min CPU Cores", + "label.max.cpu.cores":"Max CPU Cores", + "label.number.of.clusters":"Number of Clusters", + "label.number.of.cpu.sockets":"The Number of CPU Sockets", + "label.number.of.hosts":"Number of Hosts", + "label.number.of.management.servers":"Number of Management Servers", + "label.number.of.pods":"Number of Pods", + "label.number.of.system.vms":"Number of System VMs", + "label.number.of.virtual.routers":"Number of Virtual Routers", + "label.number.of.zones":"Number of Zones", + "label.numretries":"Number of Retries", + "label.ocfs2":"OCFS2", + "label.of.month":"of month", + "label.offer.ha":"Offer HA", + "label.ok":"OK", + "label.openDaylight":"OpenDaylight", + "label.opendaylight.controller":"OpenDaylight Controller", + "label.opendaylight.controllerdetail":"OpenDaylight Controller Details", + "label.opendaylight.controllers":"OpenDaylight Controllers", + "label.operation": "Operation", + "label.operator":"Operator", + "label.optional":"Optional", + "label.order":"Order", + "label.os.preference":"OS Preference", + "label.os.type":"OS Type", + "label.other":"Other", + "label.outofbandmanagement":"Out-of-band Management", + "label.outofbandmanagement.action":"Action", + "label.outofbandmanagement.action.issue":"Issue Out-of-band Management Power Action", + "label.outofbandmanagement.address":"Address", + "label.outofbandmanagement.changepassword":"Change Out-of-band Management Password", + "label.outofbandmanagement.configure":"Configure Out-of-band Management", + "label.outofbandmanagement.disable":"Disable Out-of-band Management", + "label.outofbandmanagement.driver":"Driver", + "label.outofbandmanagement.enable":"Enable Out-of-band Management", + "label.outofbandmanagement.password":"Password", + "label.outofbandmanagement.port":"Port", + "label.outofbandmanagement.reenterpassword":"Re-enter Password", + "label.outofbandmanagement.username":"Username", + "label.override.guest.traffic":"Override Guest-Traffic", + "label.override.public.traffic":"Override Public-Traffic", + "label.ovf.properties":"OVF Properties", + "label.ovm.traffic.label":"OVM traffic label", + "label.ovm3.cluster":"Native Clustering", + "label.ovm3.pool":"Native Pooling", + "label.ovm3.traffic.label":"OVM3 traffic label", + "label.ovm3.vip":"Master Vip IP", + "label.ovs":"OVS", + "label.owned.public.ips":"Owned Public IP Addresses", + "label.owner.account":"Owner Account", + "label.owner.domain":"Owner Domain", + "label.palo.alto.details":"Palo Alto details", + "label.parent.domain":"Parent Domain", + "label.passive":"Passive", + "label.password":"Password", + "label.password.enabled":"Password Enabled", + "label.password.lower":"password", + "label.password.reset.confirm":"Password has been reset to ", + "label.path":"Path", + "label.perfect.forward.secrecy":"Perfect Forward Secrecy", + "label.permission":"Permission", + "label.persistent":"Persistent ", + "label.physical.network":"Physical Network", + "label.physical.network.ID":"Physical network ID", + "label.physical.network.name":"Physical network name", + "label.ping.path":"Ping Path", + "label.planner.mode":"Planner mode", + "label.please.complete.the.following.fields":"Please complete the following fields", + "label.please.specify.netscaler.info":"Please specify Netscaler info", + "label.please.wait":"Please Wait", + "label.plugin.details":"Plugin details", + "label.plugins":"Plugins", + "label.pod":"Pod", + "label.pod.dedicated":"Pod Dedicated", + "label.pod.name":"Pod name", + "label.pods":"Pods", + "label.polling.interval.sec":"Polling Interval (in sec)", + "label.port":"Port", + "label.port.forwarding":"Port Forwarding", + "label.port.forwarding.policies":"Port forwarding policies", + "label.port.range":"Port Range", + "label.portable.ip":"Portable IP", + "label.portable.ip.range.details":"Portable IP Range details", + "label.portable.ip.ranges":"Portable IP Ranges", + "label.portable.ips":"Portable IPs", + "label.powerstate":"Power State", + "label.prev":"Prev", + "label.previous":"Previous", + "label.primary.allocated":"Primary Storage Allocated", + "label.primary.network":"Primary Network", + "label.primary.storage":"Primary Storage", + "label.primary.storage.count":"Primary Storage Pools", + "label.primary.storage.limits":"Primary Storage limits (GiB)", + "label.primary.used":"Primary Storage Used", + "label.private.Gateway":"Private Gateway", + "label.private.interface":"Private Interface", + "label.private.ip":"Private IP Address", + "label.private.ip.range":"Private IP Range", + "label.private.ips":"Private IP Addresses", + "label.private.key":"Private Key", + "label.private.network":"Private network", + "label.private.port":"Private Port", + "label.private.registry":"Private registry", + "label.private.zone":"Private Zone", + "label.privatekey":"PKCS#8 Private Key", + "label.privatekey.name":"Private Key", + "label.privatekey.password":"Private Key Password", + "label.profile":"Profile", + "label.project":"Project", + "label.project.dashboard":"Project dashboard", + "label.project.id":"Project ID", + "label.project.ids":"Project IDs", + "label.project.invite":"Invite to project", + "label.project.name":"Project name", + "label.project.view":"Project View", + "label.projects":"Projects", + "label.promiscuous.mode":"Promiscuous Mode", + "label.protocol":"Protocol", + "label.protocol.number":"Protocol Number", + "label.protocol.number.short" : "#Protocol", + "label.provider":"Provider", + "label.providers":"Providers", + "label.public":"Public", + "label.public.interface":"Public Interface", + "label.public.ip":"Public IP Address", + "label.public.ips":"Public IP Addresses", + "label.public.key":"Public Key", + "label.public.lb":"Public LB", + "label.public.load.balancer.provider":"Public Load Balancer Provider", + "label.public.network":"Public network", + "label.public.port":"Public Port", + "label.public.traffic":"Public traffic", + "label.public.traffic.vswitch.name":"Public Traffic vSwitch Name", + "label.public.traffic.vswitch.type":"Public Traffic vSwitch Type", + "label.public.zone":"Public Zone", + "label.purpose":"Purpose", + "label.qos.type":"QoS Type", + "label.quickview":"Quickview", + "label.quiesce.vm":"Quiesce VM", + "label.quiet.time.sec":"Quiet Time (in sec)", + "label.quota.add.credits":"Add Credits", + "label.quota.balance":"Balance", + "label.quota.configuration":"Quota Configuration", + "label.quota.configure":"Configure Quota", + "label.quota.credit":"Credit", + "label.quota.credits":"Credits", + "label.quota.date":"Date", + "label.quota.dates":"Update Dates", + "label.quota.description":"Quota Description", + "label.quota.email.body":"Body", + "label.quota.email.lastupdated":"Last Update", + "label.quota.email.subject":"Subject", + "label.quota.email.template":"Email Template", + "label.quota.enddate":"End Date", + "label.quota.endquota":"End Quota", + "label.quota.enforcequota":"Enforce Quota", + "label.quota.fullsummary":"All Accounts", + "label.quota.minbalance":"Min Balance", + "label.quota.remove":"Remove Quota", + "label.quota.startdate":"Start Date", + "label.quota.startquota":"Start Quota", + "label.quota.state":"State", + "label.quota.statement":"Statement", + "label.quota.statement.balance":"Quota Balance", + "label.quota.statement.bydates":"Statement", + "label.quota.statement.quota":"Quota Usage", + "label.quota.statement.tariff":"Quota Tariff", + "label.quota.summary":"Summary", + "label.quota.tariff":"Tariff", + "label.quota.tariff.edit":"Edit Tariff", + "label.quota.tariff.effectivedate":"Effective Date", + "label.quota.tariff.value":"Tariff Value", + "label.quota.total":"Total", + "label.quota.totalusage":"Total Usage", + "label.quota.type.name":"Usage Type", + "label.quota.type.unit":"Usage Unit", + "label.quota.usage":"Quota Consumption", + "label.quota.value":"Quota Value", + "label.rbd":"RBD", + "label.rbd.id":"Cephx user", + "label.rbd.monitor":"Ceph monitor", + "label.rbd.pool":"Ceph pool", + "label.rbd.secret":"Cephx secret", + "label.reboot":"Reboot", + "label.recent.errors":"Recent Errors", + "label.recover.vm":"Recover VM", + "label.redundant.router":"Redundant Router", + "label.redundant.router.capability":"Redundant router capability", + "label.redundant.state":"Redundant state", + "label.redundant.vpc":"Redundant VPC", + "label.refresh":"Refresh", + "label.refresh.blades":"Refresh Blades", + "label.region":"Region", + "label.region.details":"Region details", + "label.regionlevelvpc":"Region Level VPC", + "label.reinstall.vm":"Reinstall VM", + "label.related":"Related", + "label.release.account":"Release from Account", + "label.release.account.lowercase":"Release from account", + "label.release.dedicated.cluster":"Release Dedicated Cluster", + "label.release.dedicated.host":"Release Dedicated Host", + "label.release.dedicated.pod":"Release Dedicated Pod", + "label.release.dedicated.vlan.range":"Release dedicated VLAN range", + "label.release.dedicated.zone":"Release Dedicated Zone", + "label.remind.later":"Remind me later", + "label.remove.ACL":"Remove ACL", + "label.remove.egress.rule":"Remove egress rule", + "label.remove.from.load.balancer":"Removing instance from load balancer", + "label.remove.ingress.rule":"Remove ingress rule", + "label.remove.ip.range":"Remove IP range", + "label.remove.ldap":"Remove LDAP", + "label.remove.management.ip.range":"Remove Management IP Range", + "label.remove.network.offering":"Remove network offering", + "label.remove.pf":"Remove port forwarding rule", + "label.remove.project.account":"Remove account from project", + "label.remove.region":"Remove Region", + "label.remove.rule":"Remove rule", + "label.remove.ssh.key.pair":"Remove SSH Key Pair", + "label.remove.static.nat.rule":"Remove static NAT rule", + "label.remove.static.route":"Remove static route", + "label.remove.this.physical.network":"Remove this physical network", + "label.remove.tier":"Remove tier", + "label.remove.vm.from.lb":"Remove VM from load balancer rule", + "label.remove.vm.load.balancer":"Remove VM from load balancer", + "label.remove.vmware.datacenter":"Remove VMware datacenter", + "label.remove.vpc":"Remove VPC", + "label.remove.vpc.offering":"Remove VPC offering", + "label.removing":"Removing", + "label.removing.user":"Removing User", + "label.reource.id":"Resource ID", + "label.replace.acl":"Replace ACL", + "label.replace.acl.list":"Replace ACL List", + "label.required":"Required", + "label.requires.upgrade":"Requires Upgrade", + "label.reserved.ip.range":"Reserved IP Range", + "label.reserved.system.gateway":"Reserved system gateway", + "label.reserved.system.ip":"Reserved System IP", + "label.reserved.system.netmask":"Reserved system netmask", + "label.reset.VPN.connection":"Reset VPN connection", + "label.reset.ssh.key.pair":"Reset SSH Key Pair", + "label.reset.ssh.key.pair.on.vm":"Reset SSH Key Pair on VM", + "label.resetVM":"Reset VM", + "label.resize.new.offering.id":"New Offering", + "label.resize.new.size":"New Size (GB)", + "label.resize.shrink.ok":"Shrink OK", + "label.resource":"Resource", + "label.resource.limit.exceeded":"Resource Limit Exceeded", + "label.resource.limits":"Resource Limits", + "label.resource.name":"Resource Name", + "label.resource.state":"Resource state", + "label.resources":"Resources", + "label.response.timeout.in.sec":"Response Timeout (in sec)", + "label.restart.network":"Restart network", + "label.restart.required":"Restart required", + "label.restart.vpc":"Restart VPC", + "label.restore":"Restore", + "label.retry.interval":"Retry Interval", + "label.review":"Review", + "label.revoke.project.invite":"Revoke invitation", + "label.role":"Role", + "label.roles":"Roles", + "label.roletype":"Role Type", + "label.root.certificate":"Root certificate", + "label.root.disk.controller":"Root disk controller", + "label.root.disk.offering":"Root Disk Offering", + "label.root.disk.size":"Root disk size (GB)", + "label.router.vm.scaled.up":"Router VM Scaled Up", + "label.router.health.checks":"Health Checks", + "label.router.health.check.name":"Check name", + "label.router.health.check.type":"Type", + "label.router.health.check.success":"Success", + "label.router.health.check.last.updated":"Last updated", + "label.router.health.check.details":"Details", + "label.routing":"Routing", + "label.routing.host":"Routing Host", + "label.rule":"Rule", + "label.rule.number":"Rule Number", + "label.rule.number.short": "#Rule", + "label.rules":"Rules", + "label.run.diagnostics.type":"Type", + "label.run.diagnostics.destination":"Destination", + "label.run.diagnostics.extra":"Extra Arguments", + "label.running.vms":"Running VMs", + "label.s3.access_key":"Access Key", + "label.s3.bucket":"Bucket", + "label.s3.connection_timeout":"Connection Timeout", + "label.s3.endpoint":"Endpoint", + "label.s3.max_error_retry":"Max Error Retry", + "label.s3.nfs.path":"S3 NFS Path", + "label.s3.nfs.server":"S3 NFS Server", + "label.s3.secret_key":"Secret Key", + "label.s3.socket_timeout":"Socket Timeout", + "label.s3.use_https":"Use HTTPS", + "label.saml.enable":"Authorize SAML SSO", + "label.saml.entity":"Identity Provider", + "label.saturday":"Saturday", + "label.save":"Save", + "label.save.and.continue":"Save and continue", + "label.save.changes":"Save changes", + "label.saving.processing":"Saving....", + "label.scale.kubernetes.cluster":"Scale Kubernetes cluster", + "label.scale.up.policy":"SCALE UP POLICY", + "label.scaledown.policy":"ScaleDown Policy", + "label.scaleup.policy":"ScaleUp Policy", + "label.scope":"Scope", + "label.search":"Search", + "label.secondary.ips":"Secondary IPs", + "label.secondary.isolated.vlan.id":"Secondary Isolated VLAN ID", + "label.secondary.isolated.vlan.type":"Secondary Isolated VLAN Type", + "label.secondary.isolated.vlan.type.community":"Community", + "label.secondary.isolated.vlan.type.isolated":"Isolated", + "label.secondary.isolated.vlan.type.none":"None", + "label.secondary.isolated.vlan.type.promiscuous":"Promiscuous", + "label.secondary.staging.store":"Secondary Staging Store", + "label.secondary.staging.store.details":"Secondary Staging Store details", + "label.secondary.storage":"Secondary Storage", + "label.secondary.storage.count":"Secondary Storage Pools", + "label.secondary.storage.details":"Secondary storage details", + "label.secondary.storage.limits":"Secondary Storage limits (GiB)", + "label.secondary.storage.vm":"Secondary storage VM", + "label.secondary.used":"Secondary Storage Used", + "label.secret.key":"Secret Key", + "label.security.group":"Security Group", + "label.security.group.name":"Security Group Name", + "label.security.groups":"Security Groups", + "label.security.groups.enabled":"Security Groups Enabled", + "label.select":"Select", + "label.select-view":"Select view", + "label.select.a.template":"Select a template", + "label.select.a.zone":"Select a zone", + "label.select.deployment.infrastructure":"Select deployment infrastructure", + "label.select.instance":"Select instance", + "label.select.host":"Select host", + "label.select.instance.to.attach.volume.to":"Select instance to attach volume to", + "label.select.iso.or.template":"Select ISO or template", + "label.select.offering":"Select offering", + "label.select.project":"Select Project", + "label.select.region":"Select region", + "label.select.template":"Select Template", + "label.select.tier":"Select Tier", + "label.select.vm.for.static.nat":"Select VM for static NAT", + "label.semantic.version":"Semantic version", + "label.sent":"Sent", + "label.server":"Server", + "label.service.capabilities":"Service Capabilities", + "label.service.offering":"Service Offering", + "label.service.offering.details":"Service offering details", + "label.service.state":"Service State", + "label.services":"Services", + "label.session.expired":"Session Expired", + "label.set.default.NIC":"Set default NIC", + "label.set.reservation": "Set reservation", + "label.set.reservation.desc": "(optional) Please specify an account to be associated with this IP range.

System VMs: Enable dedication of public IP range for SSVM and CPVM, account field disabled. Reservation strictness defined on 'system.vm.public.ip.reservation.mode.strictness'", + "label.set.up.zone.type":"Set up zone type", + "label.settings":"Settings", + "label.setup":"Setup", + "label.setup.network":"Set up Network", + "label.setup.zone":"Set up Zone", + "label.shared":"Shared", + "label.share.with":"Share With", + "label.show.advanced.settings":"Show advanced settings", + "label.show.ingress.rule":"Show Ingress Rule", + "label.shutdown.provider":"Shutdown provider", + "label.simplified.chinese.keyboard":"Simplified Chinese keyboard", + "label.site.to.site.VPN":"Site-to-site VPN", + "label.size":"Size", + "label.skip.guide":"I have used CloudStack before, skip this guide", + "label.smb.domain":"SMB Domain", + "label.smb.password":"SMB Password", + "label.smb.username":"SMB Username", + "label.snapshot":"Snapshot", + "label.snapshot.limits":"Snapshot Limits", + "label.snapshot.name":"Snapshot Name", + "label.snapshot.s":"Snapshots", + "label.snapshot.schedule":"Set up Recurring Snapshot", + "label.snapshots":"Snapshots", + "label.sockets":"CPU Sockets", + "label.source.ip.address":"Source IP Address", + "label.source.nat":"Source NAT", + "label.source.nat.supported":"SourceNAT Supported", + "label.source.port":"Source Port", + "label.specify.IP.ranges":"Specify IP ranges", + "label.specify.vlan":"Specify VLAN", + "label.specify.vxlan":"Specify VXLAN", + "label.srx":"SRX", + "label.srx.details":"SRX details", + "label.ssh.key.pair":"SSH Key Pair", + "label.ssh.key.pair.details":"SSH Key Pair Details", + "label.ssh.key.pairs":"SSH Key Pairs", + "label.sslcertificates":"SSL Certificates", + "label.standard.us.keyboard":"Standard (US) keyboard", + "label.start.IP":"Start IP", + "label.start.kuberentes.cluster":"Start Kubernetes cluster", + "label.start.lb.vm":"Start LB VM", + "label.start.port":"Start Port", + "label.start.reserved.system.IP":"Start Reserved system IP", + "label.start.rolling.maintenance":"Start Rolling Maintenance", + "label.start.rolling.maintenance.force":"Force", + "label.start.rolling.maintenance.payload":"Payload", + "label.start.vlan":"Start VLAN", + "label.start.vxlan":"Start VXLAN", + "label.state":"State", + "label.suitability": "Suitability", + "label.static.nat":"Static NAT", + "label.static.nat.enabled":"Static NAT Enabled", + "label.static.nat.to":"Static NAT to", + "label.static.nat.vm.details":"Static NAT VM Details", + "label.static.routes":"Static Routes", + "label.statistics":"Statistics", + "label.status":"Status", + "label.step.1":"Step 1", + "label.step.1.title":"Step 1: Select a Template", + "label.step.2":"Step 2", + "label.step.2.title":"Step 2: Service Offering", + "label.step.3":"Step 3", + "label.step.3.title":"Step 3: Select a Disk Offering", + "label.step.4":"Step 4", + "label.step.4.title":"Step 4: Network", + "label.step.5":"Step 5", + "label.step.5.title":"Step 5: Review", + "label.stickiness":"Stickiness", + "label.stickiness.method":"Stickiness method", + "label.sticky.cookie-name":"Cookie name", + "label.sticky.domain":"Domain", + "label.sticky.expire":"Expires", + "label.sticky.holdtime":"Hold time", + "label.sticky.indirect":"Indirect", + "label.sticky.length":"Length", + "label.sticky.mode":"Mode", + "label.sticky.name":"Sticky Name", + "label.sticky.nocache":"No cache", + "label.sticky.postonly":"Post only", + "label.sticky.prefix":"Prefix", + "label.sticky.request-learn":"Request learn", + "label.sticky.tablesize":"Table size", + "label.stop":"Stop", + "label.stop.kuberentes.cluster":"Stop Kubernetes cluster", + "label.stop.lb.vm":"Stop LB VM", + "label.stopped.vms":"Stopped VMs", + "label.storage":"Storage", + "label.storage.pool":"Storage Pool", + "label.storage.tags":"Storage Tags", + "label.storage.traffic":"Storage Traffic", + "label.storage.type":"Storage Type", + "label.storagepolicy":"Storage policy", + "label.subdomain.access":"Subdomain Access", + "label.submit":"Submit", + "label.submitted.by":"[Submitted by: ]", + "label.succeeded":"Succeeded", + "label.sunday":"Sunday", + "label.super.cidr.for.guest.networks":"Super CIDR for Guest Networks", + "label.supported.services":"Supported Services", + "label.supported.source.NAT.type":"Supported Source NAT type", + "label.supportsstrechedl2subnet":"Supports Streched L2 Subnet", + "label.supportspublicaccess":"Supports Public Access", + "label.suspend.project":"Suspend Project", + "label.switch.type":"Switch Type", + "label.system.capacity":"System Capacity", + "label.system.offering":"System Offering", + "label.system.offering.for.router":"System Offering for Router", + "label.system.service.offering":"System Service Offering", + "label.system.service.offering.details":"System service offering details", + "label.system.vm":"System VM", + "label.system.vm.details":"System VM details", + "label.system.vm.scaled.up":"System VM Scaled Up", + "label.system.vm.type":"System VM Type", + "label.system.vms":"System VMs", + "label.system.wide.capacity":"System-wide capacity", + "label.tag.key":"Tag Key", + "label.tag.value":"Tag Value", + "label.tagged":"Tagged", + "label.tags":"Tags", + "label.target.iqn":"Target IQN", + "label.task.completed":"Task completed", + "label.template":"Template", + "label.template.limits":"Template Limits", + "label.tftp.root.directory":"Tftp root directory", + "label.theme.default":"Default Theme", + "label.theme.grey":"Custom - Grey", + "label.theme.lightblue":"Custom - Light Blue", + "label.threshold":"Threshold", + "label.thursday":"Thursday", + "label.tier":"Tier", + "label.tier.details":"Tier details", + "label.time":"Time", + "label.time.colon":"Time:", + "label.time.zone":"Timezone", + "label.timeout":"Timeout", + "label.timeout.in.second ":" Timeout (seconds)", + "label.timezone":"Timezone", + "label.timezone.colon":"Timezone:", + "label.token":"Token", + "label.total.CPU":"Total CPU", + "label.total.cpu":"Total CPU", + "label.total.hosts":"Total Hosts", + "label.total.memory":"Total Memory", + "label.total.of.ip":"Total of IP Addresses", + "label.total.of.vm":"Total of VMs", + "label.total.storage":"Total Storage", + "label.total.virtual.routers":"Total of Virtual Routers", + "label.total.virtual.routers.upgrade":"Total of Virtual Routers that require upgrade", + "label.total.vms":"Total VMs", + "label.traffic.label":"Traffic label", + "label.traffic.type":"Traffic Type", + "label.traffic.types":"Traffic Types", + "label.tuesday":"Tuesday", + "label.type":"Type", + "label.type.id":"Type ID", + "label.type.lower":"type", + "label.ucs":"UCS", + "label.uk.keyboard":"UK keyboard", + "label.unavailable":"Unavailable", + "label.unhealthy.threshold":"Unhealthy Threshold", + "label.unlimited":"Unlimited", + "label.untagged":"Untagged", + "label.update.kubernetes.version":"Update Kubernetes Version", + "label.update.project.resources":"Update project resources", + "label.update.ssl":" SSL Certificate", + "label.update.ssl.cert":" SSL Certificate", + "label.update.vmware.datacenter":"Update VMware datacenter", + "label.updating":"Updating", + "label.upgrade.kubernetes.cluster":"Upgrade Kubernetes cluster", + "label.upgrade.required":"Upgrade is required", + "label.upgrade.router.newer.template":"Upgrade Router to Use Newer Template", + "label.upload":"Upload", + "label.upload.from.local":"Upload from Local", + "label.upload.iso.from.local":"Upload ISO from Local", + "label.upload.template.from.local":"Upload Template from Local", + "label.upload.volume":"Upload volume", + "label.upload.volume.from.local":"Upload Volume from Local", + "label.upload.volume.from.url":"Upload volume from URL", + "label.url":"URL", + "label.usage.interface":"Usage Interface", + "label.usage.sanity.result":"Usage Sanity Result", + "label.usage.server":"Usage Server", + "label.usage.type":"Usage Type", + "label.usage.unit":"Unit", + "label.use.vm.ip":"Use VM IP:", + "label.use.vm.ips":"Use VM IPs", + "label.used":"Used", + "label.user":"User", + "label.user.conflict":"Conflict", + "label.user.data":"User Data", + "label.user.details":"User details", + "label.user.source":"source", + "label.user.vm":"User VM", + "label.username":"Username", + "label.username.lower":"username", + "label.users":"Users", + "label.uuid":"UUID", + "label.versions":"Versions", + "label.vSwitch.type":"vSwitch Type", + "label.value":"Value", + "label.vcdcname":"vCenter DC name", + "label.vcenter":"vcenter", + "label.vcenter.cluster":"vCenter Cluster", + "label.vcenter.datacenter":"vCenter Datacenter", + "label.vcenter.datastore":"vCenter Datastore", + "label.vcenter.host":"vCenter Host", + "label.vcenter.password":"vCenter Password", + "label.vcenter.username":"vCenter Username", + "label.vcipaddress":"vCenter IP Address", + "label.version":"Version", + "label.vgpu":"VGPU", + "label.vgpu.max.resolution":"Max resolution", + "label.vgpu.max.vgpu.per.gpu":"vGPUs per GPU", + "label.vgpu.remaining.capacity":"Remaining capacity", + "label.vgpu.type":"vGPU type", + "label.vgpu.video.ram":"Video RAM", + "label.view":"View", + "label.view.all":"View all", + "label.view.console":"View console", + "label.view.more":"View more", + "label.view.secondary.ips":"View secondary IPs", + "label.viewing":"Viewing", + "label.virtual.size":"Virtual Size", + "label.virtual.appliance":"Virtual Appliance", + "label.virtual.appliance.details":"Virtual applicance details", + "label.virtual.appliances":"Virtual Appliances", + "label.virtual.machine":"Virtual Machine", + "label.virtual.machines":"Virtual Machines", + "label.virtual.network":"Virtual Network", + "label.virtual.networking":"Virtual Networking", + "label.virtual.router":"Virtual Router", + "label.virtual.routers":"Virtual Routers", + "label.virtual.routers.group.account":"Virtual Routers group by account", + "label.virtual.routers.group.cluster":"Virtual Routers group by cluster", + "label.virtual.routers.group.pod":"Virtual Routers group by pod", + "label.virtual.routers.group.zone":"Virtual Routers group by zone", + "label.vlan":"VLAN/VNI", + "label.vlan.id":"VLAN/VNI ID", + "label.vlan.only":"VLAN", + "label.vlan.range":"VLAN/VNI Range", + "label.vlan.range.details":"VLAN Range details", + "label.vlan.ranges":"VLAN Range(s)", + "label.vlan.vni.range":"VLAN/VNI Range", + "label.vlan.vni.ranges":"VLAN/VNI Range(s)", + "label.vm.add":"Add Instance", + "label.vm.destroy":"Destroy", + "label.vm.display.name":"VM display name", + "label.vm.id":"VM ID", + "label.vm.ip":"VM IP Address", + "label.vm.name":"VM name", + "label.vm.password":"Password of the VM is", + "label.vm.reboot":"Reboot", + "label.vm.start":"Start", + "label.vm.state":"VM state", + "label.vm.stop":"Stop", + "label.vmfs":"VMFS", + "label.vms":"VMs", + "label.backup":"Backups", + "label.backup.offering":"Backup Offering", + "label.backup.offering.assign":"Assign VM to backup offering", + "label.backup.offering.remove":"Remove VM from backup offering", + "label.backup.restore":"Restore VM Backup", + "label.backup.user.driven":"Allow User Driven Backups", + "label.vmsnapshot":"VM Snapshots", + "label.vmsnapshot.current":"isCurrent", + "label.vmsnapshot.memory":"Snapshot memory", + "label.vmsnapshot.parentname":"Parent", + "label.vmsnapshot.type":"Type", + "label.vmware.datacenter.id":"VMware datacenter ID", + "label.vmware.datacenter.name":"VMware datacenter Name", + "label.vmware.datacenter.vcenter":"VMware datacenter vcenter", + "label.vmware.traffic.label":"VMware traffic label", + "label.vnet":"VLAN/VNI", + "label.vnet.id":"VLAN/VNI ID", + "label.vnmc":"VNMC", + "label.vnmc.devices":"VNMC Devices", + "label.volatile":"Volatile", + "label.volgroup":"Volume Group", + "label.volume":"Volume", + "label.volume.details":"Volume details", + "label.volume.empty":"No data volumes attached to this VM", + "label.volume.ids":"Volume ID's", + "label.volume.limits":"Volume Limits", + "label.volume.migrated":"Volume migrated", + "label.volume.name":"Volume Name", + "label.volumes":"Volumes", + "label.vpc":"VPC", + "label.vpc.distributedvpcrouter":"Distributed VPC Router", + "label.vpc.id":"VPC ID", + "label.vpc.offering":"VPC Offering", + "label.vpc.offering.access":"VPC offering access", + "label.vpc.offering.details":"VPC offering details", + "label.vpc.router.details":"VPC Router Details", + "label.vpc.supportsregionlevelvpc":"Supports Region Level VPC", + "label.vpc.virtual.router":"VPC Virtual Router", + "label.tungsten":"TUNGSTEN", + "label.vpn":"VPN", + "label.vpn.customer.gateway":"VPN Customer Gateway", + "label.vpn.force.encapsulation":"Force UDP Encapsulation of ESP Packets", + "label.vpn.users":"VPN Users", + "label.vsmctrlvlanid":"Control VLAN ID", + "label.vsmpktvlanid":"Packet VLAN ID", + "label.vsmstoragevlanid":"Storage VLAN ID", + "label.vsphere.managed":"vSphere Managed", + "label.vswitch.name":"vSwitch Name", + "label.vxlan":"VXLAN", + "label.vxlan.id":"VXLAN ID", + "label.vxlan.range":"VXLAN Range", + "label.waiting":"Waiting", + "label.warn":"Warn", + "label.warn.upper":"WARN", + "label.warning":"Warning", + "label.wednesday":"Wednesday", + "label.weekly":"Weekly", + "label.welcome":"Welcome", + "label.welcome.cloud.console":"Welcome to Management Console", + "label.what.is.cloudstack":"What is CloudStack™?", + "label.xenserver.tools.version.61.plus":"Original XS Version is 6.1+", + "label.xenserver.traffic.label":"XenServer traffic label", + "label.yes":"Yes", + "label.zone":"Zone", + "label.zone.dedicated":"Zone Dedicated", + "label.zone.details":"Zone details", + "label.zone.id":"Zone ID", + "label.zone.lower":"zone", + "label.zone.name":"Zone Name", + "label.zone.step.1.title":"Step 1: Select a Network", + "label.zone.step.2.title":"Step 2: Add a Zone", + "label.zone.step.3.title":"Step 3: Add a Pod", + "label.zone.step.4.title":"Step 4: Add an IP range", + "label.zone.type":"Zone Type", + "label.zone.wide":"Zone-Wide", + "label.zoneWizard.trafficType.guest":"Guest: Traffic between end-user virtual machines", + "label.zoneWizard.trafficType.management":"Management: Traffic between CloudStack's internal resources, including any components that communicate with the Management Server, such as hosts and CloudStack system VMs", + "label.zoneWizard.trafficType.public":"Public: Traffic between the internet and virtual machines in the cloud.", + "label.zoneWizard.trafficType.storage":"Storage: Traffic between primary and secondary storage servers, such as VM templates and snapshots", + "label.zones":"Zones", + "managed.state":"Managed State", + "message.XSTools61plus.update.failed":"Failed to update Original XS Version is 6.1+ field. Error:", + "message.Zone.creation.complete":"Zone creation complete", + "message.acquire.ip.nic":"Please confirm that you would like to acquire a new secondary IP for this NIC.
NOTE: You need to manually configure the newly-acquired secondary IP inside the virtual machine.", + "message.acquire.new.ip":"Please confirm that you would like to acquire a new IP for this network.", + "message.acquire.new.ip.vpc":"Please confirm that you would like to acquire a new IP for this VPC.", + "message.acquire.public.ip":"Please select a zone from which you want to acquire your new IP from.", + "message.action.cancel.maintenance":"Your host has been successfully canceled for maintenance. This process can take up to several minutes.", + "message.action.cancel.maintenance.mode":"Please confirm that you want to cancel this maintenance.", + "message.action.change.service.warning.for.instance":"Your instance must be stopped before attempting to change its current service offering.", + "message.action.change.service.warning.for.router":"Your router must be stopped before attempting to change its current service offering.", + "message.action.delete.backup.offering":"Please confirm that you want to delete this backup offering?", + "message.action.delete.ISO":"Please confirm that you want to delete this ISO.", + "message.action.delete.ISO.for.all.zones":"The ISO is used by all zones. Please confirm that you want to delete it from all zones.", + "message.action.delete.cluster":"Please confirm that you want to delete this cluster.", + "message.action.delete.disk.offering":"Please confirm that you want to delete this disk offering.", + "message.action.delete.domain":"Please confirm that you want to delete this domain.", + "message.action.delete.external.firewall":"Please confirm that you would like to remove this external firewall. Warning: If you are planning to add back the same external firewall, you must reset usage data on the device.", + "message.action.delete.external.load.balancer":"Please confirm that you would like to remove this external load balancer. Warning: If you are planning to add back the same external load balancer, you must reset usage data on the device.", + "message.action.delete.ingress.rule":"Please confirm that you want to delete this ingress rule.", + "message.action.delete.network":"Please confirm that you want to delete this network.", + "message.action.delete.nexusVswitch":"Please confirm that you want to delete this nexus 1000v", + "message.action.delete.nic":"Please confirm that want to remove this NIC, which will also remove the associated network from the VM.", + "message.action.delete.physical.network":"Please confirm that you want to delete this physical network", + "message.action.delete.pod":"Please confirm that you want to delete this pod.", + "message.action.delete.primary.storage":"Please confirm that you want to delete this primary storage.", + "message.action.delete.secondary.storage":"Please confirm that you want to delete this secondary storage.", + "message.action.delete.security.group":"Please confirm that you want to delete this security group.", + "message.action.delete.service.offering":"Please confirm that you want to delete this service offering.", + "message.action.delete.snapshot":"Please confirm that you want to delete this snapshot.", + "message.action.delete.system.service.offering":"Please confirm that you want to delete this system service offering.", + "message.action.delete.template":"Please confirm that you want to delete this template.", + "message.action.delete.template.for.all.zones":"The template is used by all zones. Please confirm that you want to delete it from all zones.", + "message.action.delete.volume":"Please confirm that you want to delete this volume.", + "message.action.delete.vpn.user":"Please confirm that you want to delete the VPN user.", + "message.action.delete.zone":"Please confirm that you want to delete this zone.", + "message.action.destroy.instance":"Please confirm that you want to destroy this instance.", + "message.action.destroy.systemvm":"Please confirm that you want to destroy this System VM.", + "message.action.destroy.volume":"Please confirm that you want to destroy this volume.", + "message.action.disable.cluster":"Please confirm that you want to disable this cluster.", + "message.action.disable.nexusVswitch":"Please confirm that you want to disable this nexus 1000v", + "message.action.disable.physical.network":"Please confirm that you want to disable this physical network.", + "message.action.disable.pod":"Please confirm that you want to disable this pod.", + "message.action.disable.static.NAT":"Please confirm that you want to disable static NAT.", + "message.action.disable.zone":"Please confirm that you want to disable this zone.", + "message.action.download.iso":"Please confirm that you want to download this ISO.", + "message.action.download.template":"Please confirm that you want to download this template.", + "message.action.downloading.template":"Downloading template.", + "message.action.enable.cluster":"Please confirm that you want to enable this cluster.", + "message.action.enable.maintenance":"Your host has been successfully prepared for maintenance. This process can take up to several minutes or longer depending on how many VMs are currently on this host.", + "message.action.enable.nexusVswitch":"Please confirm that you want to enable this nexus 1000v", + "message.action.enable.physical.network":"Please confirm that you want to enable this physical network.", + "message.action.enable.pod":"Please confirm that you want to enable this pod.", + "message.action.enable.zone":"Please confirm that you want to enable this zone.", + "message.action.expunge.instance":"Please confirm that you want to expunge this instance.", + "message.action.force.reconnect":"Your host has been successfully forced to reconnect. This process can take up to several minutes.", + "message.action.host.enable.maintenance.mode":"Enabling maintenance mode will cause a live migration of all running instances on this host to any available host.", + "message.action.instance.reset.password":"Please confirm that you want to change the ROOT password for this virtual machine.", + "message.action.manage.cluster":"Please confirm that you want to manage the cluster.", + "message.action.primarystorage.enable.maintenance.mode":"Warning: placing the primary storage into maintenance mode will cause all VMs using volumes from it to be stopped. Do you want to continue?", + "message.action.reboot.instance":"Please confirm that you want to reboot this instance.", + "message.action.reboot.router":"All services provided by this virtual router will be interrupted. Please confirm that you want to reboot this router.", + "message.action.reboot.systemvm":"Please confirm that you want to reboot this system VM.", + "message.action.recover.volume":"Please confirm that you would like to recover this volume.", + "message.action.release.ip":"Please confirm that you want to release this IP.", + "message.action.remove.host":"Please confirm that you want to remove this host.", + "message.action.reset.password.off":"Your instance currently does not support this feature.", + "message.action.reset.password.warning":"Your instance must be stopped before attempting to change its current password.", + "message.action.restore.instance":"Please confirm that you want to restore this instance.", + "message.action.revert.snapshot":"Please confirm that you want to revert the owning volume to this snapshot.", + "message.action.secure.host":"This will restart the host agent and libvirtd process after applying new X509 certificates, please confirm?", + "message.action.settings.warning.vm.running":"Please stop the virtual machine to access settings", + "message.action.settings.warning.vm.started":"Virtual machine has been started. It needs to be stopped to access settings", + "message.action.start.instance":"Please confirm that you want to start this instance.", + "message.action.start.router":"Please confirm that you want to start this router.", + "message.action.start.systemvm":"Please confirm that you want to start this system VM.", + "message.action.stop.instance":"Please confirm that you want to stop this instance.", + "message.action.stop.router":"All services provided by this virtual router will be interrupted. Please confirm that you want to stop this router.", + "message.action.router.health.checks":"Health checks result will be fetched from router.", + "message.action.stop.systemvm":"Please confirm that you want to stop this system VM.", + "message.action.take.snapshot":"Please confirm that you want to take a snapshot of this volume.", + "message.action.unmanage.cluster":"Please confirm that you want to unmanage the cluster.", + "message.action.vmsnapshot.create":"Please confirm that you want to take a snapshot of this instance.
Please notice that the instance will be paused during the snapshoting, and resumed after snapshotting, if it runs on KVM.", + "message.action.vmsnapshot.delete":"Please confirm that you want to delete this VM snapshot.
Please notice that the instance will be paused before the snapshot deletion, and resumed after deletion, if it runs on KVM.", + "message.action.vmsnapshot.revert":"Revert VM snapshot", + "message.action.vmstoragesnapshot.create":"Please choose a volume that you want to take a snapshot of.", + "message.activate.project":"Are you sure you want to activate this project?", + "message.add.VPN.gateway":"Please confirm that you want to add a VPN Gateway", + "message.add.cluster":"Add a hypervisor managed cluster for zone , pod ", + "message.add.cluster.zone":"Add a hypervisor managed cluster for zone ", + "message.add.disk.offering":"Please specify the following parameters to add a new disk offering", + "message.add.domain":"Please specify the subdomain you want to create under this domain", + "message.add.firewall":"Add a firewall to zone", + "message.add.guest.network":"Please confirm that you would like to add a guest network", + "message.add.host":"Please specify the following parameters to add a new host", + "message.add.ip.range":"Add an IP range to public network in zone", + "message.add.ip.range.direct.network":"Add an IP range to direct network in zone ", + "message.add.ip.range.to.pod":"

Add an IP range to pod:

", + "message.add.load.balancer":"Add a load balancer to zone", + "message.add.load.balancer.under.ip":"The load balancer rule has been added under IP:", + "message.add.network":"Add a new network for zone: ", + "message.add.new.gateway.to.vpc":"Please specify the information to add a new gateway to this VPC.", + "message.add.pod":"Add a new pod for zone ", + "message.add.pod.during.zone.creation":"Each zone must contain in one or more pods, and we will add the first pod now. A pod contains hosts and primary storage servers, which you will add in a later step. First, configure a range of reserved IP addresses for CloudStack's internal management traffic. The reserved IP range must be unique for each zone in the cloud.", + "message.add.primary":"Please specify the following parameters to add a new primary storage", + "message.add.primary.storage":"Add a new Primary Storage for zone , pod ", + "message.add.region":"Please specify the required information to add a new region.", + "message.add.secondary.storage":"Add a new storage for zone ", + "message.add.service.offering":"Please fill in the following data to add a new compute offering.", + "message.add.system.service.offering":"Please fill in the following data to add a new system service offering.", + "message.add.template":"Please enter the following data to create your new template", + "message.add.volume":"Please fill in the following data to add a new volume.", + "message.added.vpc.offering":"Added VPC offering", + "message.adding.Netscaler.device":"Adding Netscaler device", + "message.adding.Netscaler.provider":"Adding Netscaler provider", + "message.adding.host":"Adding host", + "message.additional.networks.desc":"Please select additional network(s) that your virtual instance will be connected to.", + "message.admin.guide.read":"For VMware-based VMs, please read the dynamic scaling section in the admin guide before scaling. Would you like to continue?,", + "message.advanced.mode.desc":"Choose this network model if you wish to enable VLAN support. This network model provides the most flexibility in allowing administrators to provide custom network offerings such as providing firewall, vpn, or load balancer support as well as enabling direct vs virtual networking.", + "message.advanced.security.group":"Choose this if you wish to use security groups to provide guest VM isolation.", + "message.advanced.virtual":"Choose this if you wish to use zone-wide VLANs to provide guest VM isolation.", + "message.after.enable.s3":"S3-backed Secondary Storage configured. Note: When you leave this page, you will not be able to re-configure S3 again.", + "message.after.enable.swift":"Swift configured. Note: When you leave this page, you will not be able to re-configure Swift again.", + "message.alert.state.detected":"Alert state detected", + "message.allow.vpn.access":"Please enter a username and password of the user that you want to allow VPN access.", + "message.apply.snapshot.policy":"You have successfully updated your current snapshot policy.", + "message.assign.instance.another":"Please specify the account type, domain, account name and network (optional) of the new account.
If the default nic of the vm is on a shared network, CloudStack will check if the network can be used by the new account if you do not specify one network.
If the default nic of the vm is on a isolated network, and the new account has more one isolated networks, you should specify one.", + "message.attach.iso.confirm":"Please confirm that you want to attach the ISO to this virtual instance.", + "message.attach.volume":"Please fill in the following data to attach a new volume. If you are attaching a disk volume to a Windows based virtual machine, you will need to reboot the instance to see the attached disk.", + "message.basic.mode.desc":"Choose this network model if you do *not* want to enable any VLAN support. All virtual instances created under this network model will be assigned an IP directly from the network and security groups are used to provide security and segregation.", + "message.change.ipaddress":"Please confirm that you would like to change the IP address for this NIC on VM.", + "message.change.offering.confirm":"Please confirm that you wish to change the service offering of this virtual instance.", + "message.change.password":"Please change your password.", + "message.cluster.dedicated":"Cluster Dedicated", + "message.cluster.dedication.released":"Cluster dedication released", + "message.configure.all.traffic.types":"You have multiple physical networks; please configure labels for each traffic type by clicking on the Edit button.", + "message.configure.firewall.rules.allow.traffic":"Configure the rules to allow Traffic", + "message.configure.firewall.rules.block.traffic":"Configure the rules to block Traffic", + "message.configure.ldap":"Please confirm you would like to configure LDAP.", + "message.configuring.guest.traffic":"Configuring guest traffic", + "message.configuring.physical.networks":"Configuring physical networks", + "message.configuring.public.traffic":"Configuring public traffic", + "message.configuring.storage.traffic":"Configuring storage traffic", + "message.confirm.action.force.reconnect":"Please confirm that you want to force reconnect this host.", + "message.confirm.add.vnmc.provider":"Please confirm you would like to add the VNMC provider.", + "message.confirm.archive.alert":"Please confirm that you want to archive this alert.", + "message.confirm.archive.event":"Please confirm that you want to archive this event.", + "message.confirm.archive.selected.alerts":"Please confirm you would like to archive the selected alerts", + "message.confirm.archive.selected.events":"Please confirm you would like to archive the selected events", + "message.confirm.attach.disk":"Are you sure you want to attach disk?", + "message.confirm.create.volume":"Are you sure you want to create volume?", + "message.confirm.current.guest.CIDR.unchanged":"Do you want to keep the current guest network CIDR unchanged?", + "message.confirm.dedicate.cluster.domain.account":"Do you really want to dedicate this cluster to a domain/account? ", + "message.confirm.dedicate.host.domain.account":"Do you really want to dedicate this host to a domain/account? ", + "message.confirm.dedicate.pod.domain.account":"Do you really want to dedicate this pod to a domain/account? ", + "message.confirm.dedicate.zone":"Do you really want to dedicate this zone to a domain/account?", + "message.confirm.delete.BigSwitchBcf":"Please confirm that you would like to delete this BigSwitch BCF Controller", + "message.confirm.delete.BrocadeVcs":"Please confirm that you would like to delete Brocade Vcs Switch", + "message.confirm.delete.F5":"Please confirm that you would like to delete F5", + "message.confirm.delete.NetScaler":"Please confirm that you would like to delete NetScaler", + "message.confirm.delete.PA":"Please confirm that you would like to delete Palo Alto", + "message.confirm.delete.SRX":"Please confirm that you would like to delete SRX", + "message.confirm.delete.acl.list":"Are you sure you want to delete this ACL list?", + "message.confirm.delete.alert":"Are you sure you want to delete this alert ?", + "message.confirm.delete.baremetal.rack.configuration":"Please confirm that you want to delete Baremetal Rack Configuration.", + "message.confirm.delete.ciscoASA1000v":"Please confirm you want to delete CiscoASA1000v", + "message.confirm.delete.ciscovnmc.resource":"Please confirm you want to delete CiscoVNMC resource", + "message.confirm.delete.internal.lb":"Please confirm you want to delete Internal LB", + "message.confirm.delete.kubernetes.version":"Please confirm that you want to delete this Kubernetes version.", + "message.confirm.delete.secondary.staging.store":"Please confirm you want to delete Secondary Staging Store.", + "message.confirm.delete.ucs.manager":"Please confirm that you want to delete UCS Manager", + "message.confirm.destroy.kubernetes.cluster":"Please confirm that you want to destroy this Kubernetes cluster.", + "message.confirm.destroy.router":"Please confirm that you would like to destroy this router", + "message.confirm.disable.host":"Please confirm that you want to disable the host", + "message.confirm.disable.network.offering":"Are you sure you want to disable this network offering?", + "message.confirm.disable.provider":"Please confirm that you would like to disable this provider", + "message.confirm.disable.vnmc.provider":"Please confirm you would like to disable the VNMC provider.", + "message.confirm.disable.vpc.offering":"Are you sure you want to disable this VPC offering?", + "message.confirm.enable.host":"Please confirm that you want to enable the host", + "message.confirm.enable.network.offering":"Are you sure you want to enable this network offering?", + "message.confirm.enable.provider":"Please confirm that you would like to enable this provider", + "message.confirm.enable.vnmc.provider":"Please confirm you would like to enable the VNMC provider.", + "message.confirm.enable.vpc.offering":"Are you sure you want to enable this VPC offering?", + "message.confirm.force.update":"Do you want to make a force update?", + "message.confirm.join.project":"Please confirm you wish to join this project.", + "message.confirm.migrate.volume":"Do you want to migrate this volume?", + "message.confirm.refresh.blades":"Please confirm that you want to refresh blades.", + "message.confirm.release.dedicate.vlan.range":"Please confirm you want to release dedicated VLAN range", + "message.confirm.release.dedicated.cluster":"Do you want to release this dedicated cluster ?", + "message.confirm.release.dedicated.host":"Do you want to release this dedicated host ?", + "message.confirm.release.dedicated.pod":"Do you want to release this dedicated pod ?", + "message.confirm.release.dedicated.zone":"Do you want to release this dedicated zone ? ", + "message.confirm.remove.IP.range":"Please confirm that you would like to remove this IP range.", + "message.confirm.remove.event":"Are you sure you want to remove this event?", + "message.confirm.remove.load.balancer":"Please confirm you want to remove VM from load balancer", + "message.confirm.remove.network.offering":"Are you sure you want to remove this network offering?", + "message.confirm.remove.selected.alerts":"Please confirm you would like to remove the selected alerts", + "message.confirm.remove.selected.events":"Please confirm you would like to remove the selected events", + "message.confirm.remove.vmware.datacenter":"Please confirm you want to remove VMware datacenter", + "message.confirm.remove.vpc.offering":"Are you sure you want to remove this VPC offering?", + "message.confirm.replace.acl.new.one":"Do you want to replace the ACL with a new one?", + "message.confirm.scale.up.router.vm":"Do you really want to scale up the Router VM ?", + "message.confirm.scale.up.system.vm":"Do you really want to scale up the system VM ?", + "message.confirm.shutdown.provider":"Please confirm that you would like to shutdown this provider", + "message.confirm.start.kubernetes.cluster":"Please confirm that you want to start this Kubernetes cluster.", + "message.confirm.start.lb.vm":"Please confirm you want to start LB VM", + "message.confirm.stop.kubernetes.cluster":"Please confirm that you want to stop this Kubernetes cluster.", + "message.confirm.stop.lb.vm":"Please confirm you want to stop LB VM", + "message.confirm.upgrade.router.newer.template":"Please confirm that you want to upgrade router to use newer template", + "message.confirm.upgrade.routers.account.newtemplate":"Please confirm that you want to upgrade all routers in this account to use newer template", + "message.confirm.upgrade.routers.cluster.newtemplate":"Please confirm that you want to upgrade all routers in this cluster to use newer template", + "message.confirm.upgrade.routers.newtemplate":"Please confirm that you want to upgrade all routers in this zone to use newer template", + "message.confirm.upgrade.routers.pod.newtemplate":"Please confirm that you want to upgrade all routers in this pod to use newer template", + "message.copy.iso.confirm":"Please confirm that you wish to copy your ISO to", + "message.copy.template":"Copy template XXX from zone to", + "message.copy.template.confirm":"Are you sure you want to copy template?", + "message.create.template":"Are you sure you want to create template?", + "message.create.template.vm":"Create VM from template ", + "message.create.template.volume":"Please specify the following information before creating a template of your disk volume: . Creation of the template can range from several minutes to longer depending on the size of the volume.", + "message.creating.cluster":"Creating cluster", + "message.creating.guest.network":"Creating guest network", + "message.creating.physical.networks":"Creating physical networks", + "message.creating.pod":"Creating pod", + "message.creating.primary.storage":"Creating primary storage", + "message.creating.secondary.storage":"Creating secondary storage", + "message.creating.systemVM":"Creating system VMs (this may take a while)", + "message.creating.zone":"Creating zone", + "message.decline.invitation":"Are you sure you want to decline this project invitation?", + "message.dedicate.zone":"Dedicating zone", + "message.dedicated.zone.released":"Zone dedication released", + "message.delete.VPN.connection":"Please confirm that you want to delete VPN connection", + "message.delete.VPN.customer.gateway":"Please confirm that you want to delete this VPN Customer Gateway", + "message.delete.VPN.gateway":"Please confirm that you want to delete this VPN Gateway", + "message.delete.account":"Please confirm that you want to delete this account.", + "message.delete.affinity.group":"Please confirm that you would like to remove this affinity group.", + "message.delete.gateway":"Please confirm you want to delete the gateway", + "message.delete.project":"Are you sure you want to delete this project?", + "message.delete.sslcertificate":"Please confirm that you would like to delete this certificate.", + "message.delete.user":"Please confirm that you would like to delete this user.", + "message.desc.add.new.lb.sticky.rule":"Add new LB sticky rule", + "message.desc.advanced.zone":"For more sophisticated network topologies. This network model provides the most flexibility in defining guest networks and providing custom network offerings such as firewall, VPN, or load balancer support.", + "message.desc.basic.zone":"Provide a single network where each VM instance is assigned an IP directly from the network. Guest isolation can be provided through layer-3 means such as security groups (IP address source filtering).", + "message.desc.cluster":"Each pod must contain one or more clusters, and we will add the first cluster now. A cluster provides a way to group hosts. The hosts in a cluster all have identical hardware, run the same hypervisor, are on the same subnet, and access the same shared storage. Each cluster consists of one or more hosts and one or more primary storage servers.", + "message.desc.create.ssh.key.pair":"Please fill in the following data to create or register a ssh key pair.

(1) If public key is set, CloudStack will register the public key. You can use it through your private key.

(2) If public key is not set, CloudStack will create a new SSH Key pair. In this case, please copy and save the private key. CloudStack will not keep it.
", + "message.desc.created.ssh.key.pair":"Created a SSH Key Pair.", + "message.desc.host":"Each cluster must contain at least one host (computer) for guest VMs to run on, and we will add the first host now. For a host to function in CloudStack, you must install hypervisor software on the host, assign an IP address to the host, and ensure the host is connected to the CloudStack management server.

Give the host's DNS or IP address, the user name (usually root) and password, and any labels you use to categorize hosts.", + "message.desc.primary.storage":"Each cluster must contain one or more primary storage servers, and we will add the first one now. Primary storage contains the disk volumes for all the VMs running on hosts in the cluster. Use any standards-compliant protocol that is supported by the underlying hypervisor.", + "message.desc.reset.ssh.key.pair":"Please specify a ssh key pair that you would like to add to this VM. Please note the root password will be changed by this operation if password is enabled.", + "message.desc.secondary.storage":"Each zone must have at least one NFS or secondary storage server, and we will add the first one now. Secondary storage stores VM templates, ISO images, and VM disk volume snapshots. This server must be available to all hosts in the zone.

Provide the IP address and exported path.", + "message.desc.zone":"A zone is the largest organizational unit in CloudStack, and it typically corresponds to a single datacenter. Zones provide physical isolation and redundancy. A zone consists of one or more pods (each of which contains hosts and primary storage servers) and a secondary storage server which is shared by all pods in the zone.", + "message.detach.disk":"Are you sure you want to detach this disk?", + "message.detach.iso.confirm":"Please confirm that you want to detach the ISO from this virtual instance.", + "message.diagnostics.exitcode":"exitcode: var", + "message.diagnostics.stderr":"stderr: var", + "message.diagnostics.stdout":"stdout: var", + "message.disable.account":"Please confirm that you want to disable this account. By disabling the account, all users for this account will no longer have access to their cloud resources. All running virtual machines will be immediately shut down.", + "message.disable.snapshot.policy":"You have successfully disabled your current snapshot policy.", + "message.disable.user":"Please confirm that you would like to disable this user.", + "message.disable.vpn":"Are you sure you want to disable VPN?", + "message.disable.vpn.access":"Please confirm that you want to disable Remote Access VPN.", + "message.disabling.network.offering":"Disabling network offering", + "message.disabling.vpc.offering":"Disabling VPC offering", + "message.disallowed.characters":"Disallowed characters: <,>", + "message.download.diagnostics":"Please click the link to download the retrieved diagnostics:

00000", + "message.download.ISO":"Please click the link to download the ISO:

00000", + "message.download.template":"Please click the link to download the template:

00000", + "message.download.volume":"Please click the link to download the volume:

00000", + "message.download.volume.confirm":"Please confirm that you want to download this volume.", + "message.edit.account":"Edit (\"-1\" indicates no limit to the amount of resources create)", + "message.edit.confirm":"Please confirm your changes before clicking \"Save\".", + "message.edit.limits":"Please specify limits to the following resources. A \"-1\" indicates no limit to the amount of resources create.", + "message.edit.traffic.type":"Please specify the traffic label you want associated with this traffic type.", + "message.enable.account":"Please confirm that you want to enable this account.", + "message.enable.user":"Please confirm that you would like to enable this user.", + "message.enable.vpn":"Please confirm that you want Remote Access VPN enabled for this IP address.", + "message.enable.vpn.access":"VPN is currently disabled for this IP Address. Would you like to enable VPN access?", + "message.enabled.vpn":"Your Remote Access VPN is currently enabled and can be accessed via the IP", + "message.enabled.vpn.ip.sec":"Your IPSec pre-shared key is", + "message.enabled.vpn.note":"Note: VPN users are now accessed by changing views at the networks tab.", + "message.enabling.network.offering":"Enabling network offering", + "message.enabling.security.group.provider":"Enabling Security Group provider", + "message.enabling.vpc.offering":"Enabling VPC offering", + "message.enabling.zone":"Enabling zone", + "message.enabling.zone.dots":"Enabling zone...", + "message.enter.seperated.list.multiple.cidrs":"Please enter a comma separated list of CIDRs if more than one", + "message.enter.token":"Please enter the token that you were given in your invite e-mail.", + "message.generate.keys":"Please confirm that you would like to generate new keys for this user.", + "message.gslb.delete.confirm":"Please confirm you want to delete this GSLB", + "message.gslb.lb.remove.confirm":"Please confirm you want to remove load balancing from GSLB", + "message.guest.traffic.in.advanced.zone":"Guest network traffic is communication between end-user virtual machines. Specify a range of VLAN IDs to carry guest traffic for each physical network.", + "message.guest.traffic.in.basic.zone":"Guest network traffic is communication between end-user virtual machines. Specify a range of IP addresses that CloudStack can assign to guest VMs. Make sure this range does not overlap the reserved system IP range.", + "message.host.dedicated":"Host Dedicated", + "message.host.dedication.released":"Host dedication released", + "message.installWizard.click.retry":"Click the button to retry launch.", + "message.installWizard.copy.whatIsACluster":"A cluster provides a way to group hosts. The hosts in a cluster all have identical hardware, run the same hypervisor, are on the same subnet, and access the same shared storage. Virtual machine instances (VMs) can be live-migrated from one host to another within the same cluster, without interrupting service to the user. A cluster is the third-largest organizational unit within a CloudStack™ deployment. Clusters are contained within pods, and pods are contained within zones.

CloudStack™ allows multiple clusters in a cloud deployment, but for a Basic Installation, we only need one cluster.", + "message.installWizard.copy.whatIsAHost":"A host is a single computer. Hosts provide the computing resources that run the guest virtual machines. Each host has hypervisor software installed on it to manage the guest VMs (except for bare metal hosts, which are a special case discussed in the Advanced Installation Guide). For example, a Linux KVM-enabled server, a Citrix XenServer server, and an ESXi server are hosts. In a Basic Installation, we use a single host running XenServer or KVM.

The host is the smallest organizational unit within a CloudStack™ deployment. Hosts are contained within clusters, clusters are contained within pods, and pods are contained within zones.", + "message.installWizard.copy.whatIsAPod":"A pod often represents a single rack. Hosts in the same pod are in the same subnet.

A pod is the second-largest organizational unit within a CloudStack™ deployment. Pods are contained within zones. Each zone can contain one or more pods; in the Basic Installation, you will have just one pod in your zone.", + "message.installWizard.copy.whatIsAZone":"A zone is the largest organizational unit within a CloudStack™ deployment. A zone typically corresponds to a single datacenter, although it is permissible to have multiple zones in a datacenter. The benefit of organizing infrastructure into zones is to provide physical isolation and redundancy. For example, each zone can have its own power supply and network uplink, and the zones can be widely separated geographically (though this is not required).", + "message.installWizard.copy.whatIsCloudStack":"CloudStack™ is a software platform that pools computing resources to build public, private, and hybrid Infrastructure as a Service (IaaS) clouds. CloudStack™ manages the network, storage, and compute nodes that make up a cloud infrastructure. Use CloudStack™ to deploy, manage, and configure cloud computing environments.

Extending beyond individual virtual machine images running on commodity hardware, CloudStack™ provides a turnkey cloud infrastructure software stack for delivering virtual datacenters as a service - delivering all of the essential components to build, deploy, and manage multi-tier and multi-tenant cloud applications. Both open-source and Premium versions are available, with the open-source version offering nearly identical features.", + "message.installWizard.copy.whatIsPrimaryStorage":"A CloudStack™ cloud infrastructure makes use of two types of storage: primary storage and secondary storage. Both of these can be iSCSI or NFS servers, or localdisk.

Primary storage is associated with a cluster, and it stores the disk volumes of each guest VM for all the VMs running on hosts in that cluster. The primary storage server is typically located close to the hosts.", + "message.installWizard.copy.whatIsSecondaryStorage":"Secondary storage is associated with a zone, and it stores the following:

  • Templates - OS images that can be used to boot VMs and can include additional configuration information, such as installed applications
  • ISO images - OS images that can be bootable or non-bootable
  • Disk volume snapshots - saved copies of VM data which can be used for data recovery or to create new templates
", + "message.installWizard.now.building":"Now building your cloud...", + "message.installWizard.tooltip.addCluster.name":"A name for the cluster. This can be text of your choosing and is not used by CloudStack.", + "message.installWizard.tooltip.addHost.hostname":"The DNS name or IP address of the host.", + "message.installWizard.tooltip.addHost.password":"This is the password for the user named above (from your XenServer install).", + "message.installWizard.tooltip.addHost.username":"Usually root.", + "message.installWizard.tooltip.addPod.name":"A name for the pod", + "message.installWizard.tooltip.addPod.reservedSystemEndIp":"This is the IP range in the private network that the CloudStack uses to manage Secondary Storage VMs and Console Proxy VMs. These IP addresses are taken from the same subnet as computing servers.", + "message.installWizard.tooltip.addPod.reservedSystemGateway":"The gateway for the hosts in that pod.", + "message.installWizard.tooltip.addPod.reservedSystemNetmask":"The netmask in use on the subnet the guests will use.", + "message.installWizard.tooltip.addPod.reservedSystemStartIp":"This is the IP range in the private network that the CloudStack uses to manage Secondary Storage VMs and Console Proxy VMs. These IP addresses are taken from the same subnet as computing servers.", + "message.installWizard.tooltip.addPrimaryStorage.name":"The name for the storage device.", + "message.installWizard.tooltip.addPrimaryStorage.path":"(for NFS) In NFS this is the exported path from the server. Path (for SharedMountPoint). With KVM this is the path on each host that is where this primary storage is mounted. For example, \"/mnt/primary\".", + "message.installWizard.tooltip.addPrimaryStorage.server":"(for NFS, iSCSI, or PreSetup) The IP address or DNS name of the storage device.", + "message.installWizard.tooltip.addSecondaryStorage.nfsServer":"The IP address of the NFS server hosting the secondary storage", + "message.installWizard.tooltip.addSecondaryStorage.path":"The exported path, located on the server you specified above", + "message.installWizard.tooltip.addZone.dns1":"These are DNS servers for use by guest VMs in the zone. These DNS servers will be accessed via the public network you will add later. The public IP addresses for the zone must have a route to the DNS server named here.", + "message.installWizard.tooltip.addZone.dns2":"These are DNS servers for use by guest VMs in the zone. These DNS servers will be accessed via the public network you will add later. The public IP addresses for the zone must have a route to the DNS server named here.", + "message.installWizard.tooltip.addZone.internaldns1":"These are DNS servers for use by system VMs in the zone. These DNS servers will be accessed via the private network interface of the System VMs. The private IP address you provide for the pods must have a route to the DNS server named here.", + "message.installWizard.tooltip.addZone.internaldns2":"These are DNS servers for use by system VMs in the zone. These DNS servers will be accessed via the private network interface of the System VMs. The private IP address you provide for the pods must have a route to the DNS server named here.", + "message.installWizard.tooltip.addZone.name":"A name for the zone", + "message.installWizard.tooltip.configureGuestTraffic.description":"A description for your network", + "message.installWizard.tooltip.configureGuestTraffic.guestEndIp":"The range of IP addresses that will be available for allocation to guests in this zone. If one NIC is used, these IPs should be in the same CIDR as the pod CIDR.", + "message.installWizard.tooltip.configureGuestTraffic.guestGateway":"The gateway that the guests should use", + "message.installWizard.tooltip.configureGuestTraffic.guestNetmask":"The netmask in use on the subnet that the guests should use", + "message.installWizard.tooltip.configureGuestTraffic.guestStartIp":"The range of IP addresses that will be available for allocation to guests in this zone. If one NIC is used, these IPs should be in the same CIDR as the pod CIDR.", + "message.installWizard.tooltip.configureGuestTraffic.name":"A name for your network", + "message.instance.scaled.up.confirm":"Do you really want to scale Up your instance ?", + "message.instanceWizard.noTemplates":"You do not have any templates available; please add a compatible template, and re-launch the instance wizard.", + "message.ip.address.changed":"Your IP addresses may have changed; would you like to refresh the listing? Note that in this case the details pane will close.", + "message.iso.desc":"Disc image containing data or bootable media for OS", + "message.join.project":"You have now joined a project. Please switch to Project view to see the project.", + "message.launch.vm.on.private.network":"Do you wish to launch your instance on your own private dedicated network?", + "message.launch.zone":"Zone is ready to launch; please proceed to the next step.", + "message.ldap.group.import":"All The users from the given group name will be imported", + "message.link.domain.to.ldap":"Enable autosync for this domain in LDAP", + "message.listView.subselect.multi":"(Ctrl/Cmd-click)", + "message.lock.account":"Please confirm that you want to lock this account. By locking the account, all users for this account will no longer be able to manage their cloud resources. Existing resources can still be accessed.", + "message.migrate.instance.confirm":"Please confirm the host you wish to migrate the virtual instance to.", + "message.migrate.instance.to.host":"Please confirm that you want to migrate instance to another host.", + "message.migrate.instance.select.host":"Please select a host for migration", + "message.migrate.instance.to.ps":"Please confirm that you want to migrate instance to another primary storage.", + "message.migrate.router.confirm":"Please confirm the host you wish to migrate the router to:", + "message.migrate.systemvm.confirm":"Please confirm the host you wish to migrate the system VM to:", + "message.migrate.volume":"Please confirm that you want to migrate volume to another primary storage.", + "message.ncc.delete.confirm":"Please confirm you want to delete this NCC", + "message.network.addVM.desc":"Please specify the network that you would like to add this VM to. A new NIC will be added for this network.", + "message.network.addVMNIC":"Please confirm that you would like to add a new VM NIC for this network.", + "message.network.remote.access.vpn.configuration":"Remote Access VPN configuration has been generated, but it failed to apply. Please check connectivity of the network element, then re-try.", + "message.new.user":"Specify the following to add a new user to the account", + "message.no.affinity.groups":"You do not have any affinity groups. Please continue to the next step.", + "message.no.host.available":"No hosts are available for migration", + "message.no.more.hosts.available":"No more hosts are available for migration", + "message.no.network.support":"Your selected hypervisor, vSphere, does not have any additional network features. Please continue to step 5.", + "message.no.network.support.configuration.not.true":"You do not have any zone that has security group enabled. Thus, no additional network features. Please continue to step 5.", + "message.no.projects":"You do not have any projects.
Please create a new one from the projects section.", + "message.no.projects.adminOnly":"You do not have any projects.
Please ask your administrator to create a new project.", + "message.no.datadisk":"The multidisk template has no data disk, please continue to next step.", + "message.number.clusters":"

# of Clusters

", + "message.number.hosts":"

# of Hosts

", + "message.number.pods":"

# of Pods

", + "message.number.storage":"

# of Primary Storage Volumes

", + "message.number.zones":"

# of Zones

", + "message.outofbandmanagement.action.maintenance":"Warning host is in maintenance mode", + "message.outofbandmanagement.changepassword":"Change Out-of-band Management password", + "message.outofbandmanagement.configure":"Configure Out-of-band Management", + "message.outofbandmanagement.disable":"Disable Out-of-band Management", + "message.outofbandmanagement.enable":"Enable Out-of-band Management", + "message.outofbandmanagement.issue":"Issue Out-of-band Management Power Action", + "message.ovf.properties.available":"There are OVF properties available for customizing the selected appliance. Please edit the values accordingly.", + "message.password.has.been.reset.to":"Password has been reset to", + "message.password.of.the.vm.has.been.reset.to":"Password of the VM has been reset to", + "message.pending.projects.1":"You have pending project invitations:", + "message.pending.projects.2":"To view, please go to the projects section, then select invitations from the drop-down.", + "message.please.add.at.lease.one.traffic.range":"Please add at least one traffic range.", + "message.please.confirm.remove.ssh.key.pair":"Please confirm that you want to remove this SSH Key Pair", + "message.please.proceed":"Please proceed to the next step.", + "message.please.select.a.configuration.for.your.zone":"Please select a configuration for your zone.", + "message.please.select.a.different.public.and.management.network.before.removing":"Please select a different public and management network before removing", + "message.please.select.networks":"Please select networks for your virtual machine.", + "message.please.select.ssh.key.pair.use.with.this.vm":"Please select a ssh key pair you want this VM to use:", + "message.please.wait.while.zone.is.being.created":"Please wait while your zone is being created; this may take a while...", + "message.pod.dedication.released":"Pod dedication released", + "message.portable.ip.delete.confirm":"Please confirm you want to delete Portable IP Range", + "message.project.invite.sent":"Invite sent to user; they will be added to the project once they accept the invitation", + "message.public.traffic.in.advanced.zone":"Public traffic is generated when VMs in the cloud access the internet. Publicly-accessible IPs must be allocated for this purpose. End users can use the CloudStack UI to acquire these IPs to implement NAT between their guest network and their public network.

Provide at least one range of IP addresses for internet traffic.", + "message.public.traffic.in.basic.zone":"Public traffic is generated when VMs in the cloud access the Internet or provide services to clients over the Internet. Publicly accessible IPs must be allocated for this purpose. When a instance is created, an IP from this set of Public IPs will be allocated to the instance in addition to the guest IP address. Static 1-1 NAT will be set up automatically between the public IP and the guest IP. End users can also use the CloudStack UI to acquire additional IPs to implement static NAT between their instances and the public IP.", + "message.question.are.you.sure.you.want.to.add":"Are you sure you want to add", + "message.read.admin.guide.scaling.up":"Please read the dynamic scaling section in the admin guide before scaling up.", + "message.recover.vm":"Please confirm that you would like to recover this VM.", + "message.redirecting.region":"Redirecting to region...", + "message.register.failed":"Registration Failed", + "message.register.succeeded":"Registration Succeeded", + "message.reinstall.vm":"NOTE: Proceed with caution. This will cause the VM to be reinstalled from the template; data on the root disk will be lost. Extra data volumes, if any, will not be touched.", + "message.remove.ldap":"Are you sure you want to delete the LDAP configuration?", + "message.remove.region":"Are you sure you want to remove this region from this management server?", + "message.remove.vpc":"Please confirm that you want to remove the VPC", + "message.remove.vpn.access":"Please confirm that you want to remove VPN access from the following user.", + "message.removed.ssh.key.pair":"Removed a SSH Key Pair", + "message.reset.VPN.connection":"Please confirm that you want to reset VPN connection", + "message.reset.password.warning.notPasswordEnabled":"The template of this instance was created without password enabled", + "message.reset.password.warning.notStopped":"Your instance must be stopped before attempting to change its current password", + "message.restart.mgmt.server":"Please restart your management server(s) for your new settings to take effect.", + "message.restart.mgmt.usage.server":"Please restart your management server(s) and usage server(s) for your new settings to take effect.", + "message.restart.network":"All services provided by this network will be interrupted. Please confirm that you want to restart this network.", + "message.restart.vpc":"Please confirm that you want to restart the VPC", + "message.restart.vpc.remark":"Please confirm that you want to restart the VPC

Remark: making a non-redundant VPC redundant will force a clean up. The networks will not be available for a couple of minutes.

", + "message.restoreVM":"Do you want to restore the VM ?", + "message.role.update.fail": "Failed updating rule permission", + "message.role.ordering.fail":"Reordering of rule permissions aborted as the list has changed while you were making changes. Please try again.", + "message.security.group.usage":"(Use Ctrl-click to select all applicable security groups)", + "message.select.a.zone":"A zone typically corresponds to a single datacenter. Multiple zones help make the cloud more reliable by providing physical isolation and redundancy.", + "message.select.affinity.groups":"Please select any affinity groups you want this VM to belong to:", + "message.select.instance":"Please select an instance.", + "message.select.iso":"Please select an ISO for your new virtual instance.", + "message.select.item":"Please select an item.", + "message.select.security.groups":"Please select security group(s) for your new VM", + "message.select.template":"Please select a template for your new virtual instance.", + "message.select.tier":"Please select a tier", + "message.set.default.NIC":"Please confirm that you would like to make this NIC the default for this VM.", + "message.set.default.NIC.manual":"Please manually update the default NIC on the VM now.", + "message.setup.physical.network.during.zone.creation":"When adding an advanced zone, you need to set up one or more physical networks. Each network corresponds to a NIC on the hypervisor. Each physical network can carry one or more types of traffic, with certain restrictions on how they may be combined.

Drag and drop one or more traffic types onto each physical network.", + "message.setup.physical.network.during.zone.creation.basic":"When adding a basic zone, you can set up one physical network, which corresponds to a NIC on the hypervisor. The network carries several types of traffic.

You may also drag and drop other traffic types onto the physical network.", + "message.setup.successful":"Cloud setup successful!", + "message.snapshot.schedule":"You can set up recurring snapshot schedules by selecting from the available options below and applying your policy preference", + "message.specifiy.tag.key.value":"Please specify a tag key and value", + "message.specify.url":"Please specify URL", + "message.step.1.continue":"Please select a template or ISO to continue", + "message.step.1.desc":"Please select a template for your new virtual instance. You can also choose to select a blank template from which an ISO image can be installed onto.", + "message.step.2.continue":"Please select a service offering to continue", + "message.step.3.continue":"Please select a disk offering to continue", + "message.step.4.continue":"Please select at least one network to continue", + "message.step.4.desc":"Please select the primary network that your virtual instance will be connected to.", + "message.storage.traffic":"Traffic between CloudStack's internal resources, including any components that communicate with the Management Server, such as hosts and CloudStack system VMs. Please configure storage traffic here.", + "message.suspend.project":"Are you sure you want to suspend this project?", + "message.systems.vms.ready":"System VMs ready.", + "message.template.copying":"Template is being copied.", + "message.template.copy.select.zone":"Please select a zone to copy template.", + "message.template.desc":"OS image that can be used to boot VMs", + "message.tier.required":"Tier is required", + "message.tooltip.dns.1":"Name of a DNS server for use by VMs in the zone. The public IP addresses for the zone must have a route to this server.", + "message.tooltip.dns.2":"A second DNS server name for use by VMs in the zone. The public IP addresses for the zone must have a route to this server.", + "message.tooltip.internal.dns.1":"Name of a DNS server for use by CloudStack internal system VMs in the zone. The private IP address for the pods must have a route to this server.", + "message.tooltip.internal.dns.2":"Name of a DNS server for use by CloudStack internal system VMs in the zone. The private IP address for the pods must have a route to this server.", + "message.tooltip.network.domain":"A DNS suffix that will create a custom domain name for the network that is accessed by guest VMs.", + "message.tooltip.pod.name":"A name for this pod.", + "message.tooltip.reserved.system.gateway":"The gateway for the hosts in the pod.", + "message.tooltip.reserved.system.netmask":"The network prefix that defines the pod subnet. Uses CIDR notation.", + "message.tooltip.zone.name":"A name for the zone.", + "message.update.os.preference":"Please choose a OS preference for this host. All virtual instances with similar preferences will be first allocated to this host before choosing another.", + "message.update.resource.count":"Please confirm that you want to update resource counts for this account.", + "message.update.ssl":"Please submit a new X.509 compliant SSL certificate chain to be updated to each console proxy and secondary storage virtual instance:", + "message.update.ssl.failed":"Failed to update SSL Certificate.", + "message.update.ssl.succeeded":"Update SSL Certificates succeeded", + "message.validate.URL":"Please enter a valid URL.", + "message.validate.accept":"Please enter a value with a valid extension.", + "message.validate.creditcard":"Please enter a valid credit card number.", + "message.validate.date":"Please enter a valid date.", + "message.validate.date.ISO":"Please enter a valid date (ISO).", + "message.validate.digits":"Please enter only digits.", + "message.validate.email.address":"Please enter a valid email address.", + "message.validate.equalto":"Please enter the same value again.", + "message.validate.fieldrequired":"This field is required.", + "message.validate.fixfield":"Please fix this field.", + "message.validate.instance.name":"Instance name can not be longer than 63 characters. Only ASCII letters a~z, A~Z, digits 0~9, hyphen are allowed. Must start with a letter and end with a letter or a digit.", + "message.validate.invalid.characters":"Invalid characters found; please correct.", + "message.validate.max":"Please enter a value less than or equal to {0}.", + "message.validate.maxlength":"Please enter no more than {0} characters.", + "message.validate.minlength":"Please enter at least {0} characters.", + "message.validate.number":"Please enter a valid number.", + "message.validate.range":"Please enter a value between {0} and {1}.", + "message.validate.range.length":"Please enter a value between {0} and {1} characters long.", + "message.virtual.network.desc":"A dedicated virtualized network for your account. The broadcast domain is contained within a VLAN and all public network access is routed out by a virtual router.", + "message.vm.create.template.confirm":"Create Template will reboot the VM automatically.", + "message.vm.review.launch":"Please review the following information and confirm that your virtual instance is correct before launch.", + "message.vnmc.available.list":"VNMC is not available from provider list.", + "message.vnmc.not.available.list":"VNMC is not available from provider list.", + "message.volume.create.template.confirm":"Please confirm that you wish to create a template for this disk volume. Creation of the template can range from several minutes to longer depending on the size of the volume.", + "message.volume.root.shrink.disk.size" :"Shrink operation on ROOT volume not supported", + "message.waiting.for.builtin.templates.to.load":"Waiting for builtin templates to load...", + "message.you.must.have.at.least.one.physical.network":"You must have at least one physical network", + "message.your.cloudstack.is.ready":"Your CloudStack is ready!", + "message.zone.creation.complete.would.you.like.to.enable.this.zone":"Zone creation complete. Would you like to enable this zone?", + "message.zone.no.network.selection":"The zone you selected does not have any choices for network selection.", + "message.zone.step.1.desc":"Please select a network model for your zone.", + "message.zone.step.2.desc":"Please enter the following info to add a new zone", + "message.zone.step.3.desc":"Please enter the following info to add a new pod", + "message.zoneWizard.enable.local.storage":"WARNING: If you enable local storage for this zone, you must do the following, depending on where you would like your system VMs to launch:

1. If system VMs need to be launched in shared primary storage, shared primary storage needs to be added to the zone after creation. You must also start the zone in a disabled state.

2. If system VMs need to be launched in local primary storage, system.vm.use.local.storage needs to be set to true before you enable the zone.


Would you like to continue?", + "messgae.validate.min":"Please enter a value greater than or equal to {0}.", + "mode":"Mode", + "network.rate":"Network Rate", + "notification.reboot.instance":"Reboot instance", + "notification.start.instance":"Start instance", + "notification.stop.instance":"Stop instance", + "side.by.side":"Side by Side", + "state.Accepted":"Accepted", + "state.Active":"Active", + "state.Allocated":"Allocated", + "state.Allocating":"Allocating", + "state.BackedUp":"Backed Up", + "state.BackingUp":"Backing Up", + "state.Completed":"Completed", + "state.Creating":"Creating", + "state.Declined":"Declined", + "state.Destroyed":"Destroyed", + "state.Disabled":"Disabled", + "state.Enabled":"Enabled", + "state.Error":"Error", + "state.Expunging":"Expunging", + "state.Migrating":"Migrating", + "state.Pending":"Pending", + "state.Ready":"Ready", + "state.Running":"Running", + "state.Starting":"Starting", + "state.Stopped":"Stopped", + "state.Stopping":"Stopping", + "state.Suspended":"Suspended", + "state.detached":"Detached", + "title.upload.volume":"Upload Volume", + "ui.listView.filters.all":"All", + "ui.listView.filters.mine":"Mine"}; diff --git a/ui/scripts/configuration.js b/ui/scripts/configuration.js new file mode 100644 index 000000000000..abf623747e3c --- /dev/null +++ b/ui/scripts/configuration.js @@ -0,0 +1,5965 @@ +// 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. + +(function(cloudStack, $) { + + var requiredNetworkOfferingExists = false; + var networkServiceObjs = [], + serviceCheckboxNames = []; + var serviceFields = []; + + cloudStack.sections.configuration = { + title: 'label.menu.service.offerings', + id: 'configuration', + sectionSelect: { + preFilter: function(args) { + if(isAdmin()) + return ["serviceOfferings", "systemServiceOfferings", "diskOfferings", "networkOfferings", "vpcOfferings", "backupOfferings"]; + else if(isDomainAdmin()) + return ["serviceOfferings", "diskOfferings"]; + else + return null; + }, + label: 'label.select.offering' + }, + sections: { + serviceOfferings: { + type: 'select', + title: 'label.compute.offerings', + listView: { + id: 'serviceOfferings', + label: 'label.menu.service.offerings', + fields: { + name: { + label: 'label.name', + editable: true + }, + displaytext: { + label: 'label.description' + } + }, + + reorder: cloudStack.api.actions.sort('updateServiceOffering', 'serviceOfferings'), + + actions: { + add: { + label: 'label.add.compute.offering', + + messages: { + confirm: function(args) { + return 'message.add.service.offering'; + }, + notification: function(args) { + return 'label.add.compute.offering'; + } + }, + + createForm: { + title: 'label.add.compute.offering', + preFilter: function(args) { + if (isAdmin()) { + } else { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); + args.$form.find('.form-item[rel=isPublic]').hide(); + args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown + args.$form.find('.form-item[rel=deploymentPlanner]').hide(); + args.$form.find('.form-item[rel=plannerMode]').hide(); + args.$form.find('.form-item[rel=storageTags]').hide(); + args.$form.find('.form-item[rel=hostTags]').hide(); + } + }, + fields: { + name: { + label: 'label.name', + docID: 'helpComputeOfferingName', + validation: { + required: true + } + }, + description: { + label: 'label.description', + docID: 'helpComputeOfferingDescription', + validation: { + required: true + } + }, + storageType: { + label: 'label.storage.type', + docID: 'helpComputeOfferingStorageType', + select: function(args) { + var items = []; + items.push({ + id: 'shared', + description: 'shared' + }); + items.push({ + id: 'local', + description: 'local' + }); + args.response.success({ + data: items + }); + } + }, + provisioningType: { + label: 'label.disk.provisioningtype', + docID: 'helpComputeOfferingProvisioningType', + select: function(args) { + var items = []; + items.push({ + id: 'thin', + description: 'thin' + }); + items.push({ + id: 'sparse', + description: 'sparse' + }); + items.push({ + id: 'fat', + description: 'fat' + }); + args.response.success({ + data: items + }); + } + }, + cacheMode: { + label: 'label.cache.mode', + docID: 'helpDiskOfferingCacheMode', + select: function (args) { + var items = []; + items.push({ + id: 'none', + description: 'No disk cache' + }); + items.push({ + id: 'writeback', + description: 'Write-back disk caching' + }); + items.push({ + id: "writethrough", + description: 'Write-through' + }); + args.response.success({ + data: items + }) + } + }, + offeringType: { + label: 'label.compute.offering.type', + docID: 'helpComputeOfferingType', + select: function(args) { + var items = []; + items.push({ + id: 'fixed', + description: _l('label.compute.offering.fixed') + }); + items.push({ + id: 'customConstrained', + description: _l('label.compute.offering.custom.constrained') + }); + items.push({ + id: 'customUnconstrained', + description: _l('label.compute.offering.custom.unconstrained') + }); + + args.response.success({ + data: items + }); + + args.$select.change(function() { + var $form = $(this).closest('form'); + + var $cpuNumber = $form.find('.form-item[rel=cpuNumber]'); + var $cpuSpeed = $form.find('.form-item[rel=cpuSpeed]'); + var $memory = $form.find('.form-item[rel=memory]'); + + var $minCPUNumber = $form.find('.form-item[rel=minCPUNumber]'); + var $maxCPUNumber = $form.find('.form-item[rel=maxCPUNumber]'); + var $minMemory = $form.find('.form-item[rel=minMemory]'); + var $maxMemory = $form.find('.form-item[rel=maxMemory]'); + + var type = $(this).val(); + if (type == 'fixed') { + $minCPUNumber.hide(); + $maxCPUNumber.hide(); + $minMemory.hide(); + $maxMemory.hide(); + + $cpuNumber.css('display', 'inline-block'); + $cpuSpeed.css('display', 'inline-block'); + $memory.css('display', 'inline-block'); + } else if (type == 'customConstrained') { + $cpuNumber.hide(); + $memory.hide(); + + $cpuSpeed.css('display', 'inline-block'); + $minCPUNumber.css('display', 'inline-block'); + $maxCPUNumber.css('display', 'inline-block'); + $minMemory.css('display', 'inline-block'); + $maxMemory.css('display', 'inline-block'); + } else { + $cpuNumber.hide(); + $memory.hide(); + $cpuSpeed.hide(); + $minCPUNumber.hide(); + $maxCPUNumber.hide(); + $minMemory.hide(); + $maxMemory.hide(); + } + }); + } + }, + cpuNumber: { + label: 'label.num.cpu.cores', + dependsOn: 'isCustomized', + docID: 'helpComputeOfferingCPUCores', + validation: { + required: true, + number: true + } + }, + cpuSpeed: { + label: 'label.cpu.mhz', + dependsOn: 'isCustomized', + docID: 'helpComputeOfferingCPUMHz', + validation: { + required: true, + number: true + } + }, + memory: { + label: 'label.memory.mb', + dependsOn: 'isCustomized', + docID: 'helpComputeOfferingMemory', + validation: { + required: true, + number: true + } + }, + // Custom Compute Offering + minCPUNumber: { + label: 'label.min.cpu.cores', + docID: 'helpComputeOfferingMinCPUCores', + validation: { + required: true, + number: true + } + }, + maxCPUNumber: { + label: 'label.max.cpu.cores', + docID: 'helpComputeOfferingMaxCPUCores', + validation: { + required: true, + number: true + } + }, + minMemory: { + label: 'label.memory.minimum.mb', + docID: 'helpComputeOfferingMinMemory', + validation: { + required: true, + number: true + } + }, + maxMemory: { + label: 'label.memory.maximum.mb', + docID: 'helpComputeOfferingMaxMemory', + validation: { + required: true, + number: true + } + }, + networkRate: { + label: 'label.network.rate', + docID: 'helpComputeOfferingNetworkRate', + validation: { + required: false, //optional + number: true + } + }, + qosType: { + label: 'label.qos.type', + docID: 'helpDiskOfferingQoSType', + select: function(args) { + var items = []; + items.push({ + id: '', + description: '' + }); + items.push({ + id: 'hypervisor', + description: 'hypervisor' + }); + items.push({ + id: 'storage', + description: 'storage' + }); + args.response.success({ + data: items + }); + + args.$select.change(function() { + var $form = $(this).closest('form'); + var $isCustomizedIops = $form.find('.form-item[rel=isCustomizedIops]'); + var $minIops = $form.find('.form-item[rel=minIops]'); + var $maxIops = $form.find('.form-item[rel=maxIops]'); + var $hypervisorSnapshotReserve = $form.find('.form-item[rel=hypervisorSnapshotReserve]'); + var $diskBytesReadRate = $form.find('.form-item[rel=diskBytesReadRate]'); + var $diskBytesWriteRate = $form.find('.form-item[rel=diskBytesWriteRate]'); + var $diskIopsReadRate = $form.find('.form-item[rel=diskIopsReadRate]'); + var $diskIopsWriteRate = $form.find('.form-item[rel=diskIopsWriteRate]'); + + var qosId = $(this).val(); + + if (qosId == 'storage') { // Storage QoS + $diskBytesReadRate.hide(); + $diskBytesWriteRate.hide(); + $diskIopsReadRate.hide(); + $diskIopsWriteRate.hide(); + + $isCustomizedIops.css('display', 'inline-block'); + + if ($isCustomizedIops.find('input[type=checkbox]').is(':checked')) { + $minIops.hide(); + $maxIops.hide(); + } else { + $minIops.css('display', 'inline-block'); + $maxIops.css('display', 'inline-block'); + } + + $hypervisorSnapshotReserve.css('display', 'inline-block'); + } else if (qosId == 'hypervisor') { // Hypervisor Qos + $isCustomizedIops.hide(); + $minIops.hide(); + $maxIops.hide(); + $hypervisorSnapshotReserve.hide(); + + $diskBytesReadRate.css('display', 'inline-block'); + $diskBytesWriteRate.css('display', 'inline-block'); + $diskIopsReadRate.css('display', 'inline-block'); + $diskIopsWriteRate.css('display', 'inline-block'); + } else { // No Qos + $diskBytesReadRate.hide(); + $diskBytesWriteRate.hide(); + $diskIopsReadRate.hide(); + $diskIopsWriteRate.hide(); + $isCustomizedIops.hide(); + $minIops.hide(); + $maxIops.hide(); + $hypervisorSnapshotReserve.hide(); + } + }); + } + }, + isCustomizedIops: { + label: 'label.custom.disk.iops', + docID: 'helpDiskOfferingCustomDiskIops', + isBoolean: true, + isReverse: true, + isChecked: false + }, + minIops: { + label: 'label.disk.iops.min', + docID: 'helpDiskOfferingDiskIopsMin', + dependsOn: 'isCustomizedIops', + validation: { + required: false, + number: true + } + }, + maxIops: { + label: 'label.disk.iops.max', + docID: 'helpDiskOfferingDiskIopsMax', + dependsOn: 'isCustomizedIops', + validation: { + required: false, + number: true + } + }, + hypervisorSnapshotReserve: { + label: 'label.hypervisor.snapshot.reserve', + docID: 'helpDiskOfferingHypervisorSnapshotReserve', + validation: { + required: false, + number: true + } + }, + diskBytesReadRate: { + label: 'label.disk.bytes.read.rate', + docID: 'helpComputeOfferingDiskBytesReadRate', + validation: { + required: false, //optional + number: true + } + }, + diskBytesWriteRate: { + label: 'label.disk.bytes.write.rate', + docID: 'helpComputeOfferingDiskBytesWriteRate', + validation: { + required: false, //optional + number: true + } + }, + diskIopsReadRate: { + label: 'label.disk.iops.read.rate', + docID: 'helpComputeOfferingDiskIopsReadRate', + validation: { + required: false, //optional + number: true + } + }, + diskIopsWriteRate: { + label: 'label.disk.iops.write.rate', + docID: 'helpComputeOfferingDiskIopsWriteRate', + validation: { + required: false, //optional + number: true + } + }, + offerHA: { + label: 'label.offer.ha', + docID: 'helpComputeOfferingHA', + isBoolean: true, + isChecked: false + }, + storageTags: { + label: 'label.storage.tags', + docID: 'helpComputeOfferingStorageType', + isTokenInput: true, + dataProvider: function(args) { + $.ajax({ + url: createURL("listStorageTags"), + dataType: "json", + success: function(json) { + var item = json.liststoragetagsresponse.storagetag; + var tags = []; + + if (item != null) + { + tags = $.map(item, function(tag) { + return { + id: tag.name, + name: tag.name + }; + }); + } + + args.response.success({ + data: tags, + hintText: _l('hint.type.part.storage.tag'), + noResultsText: _l('hint.no.storage.tags') + }); + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + + args.response.error(errorMsg); + } + }); + } + }, + hostTags: { //Only one single host tag is supported at server-side. Multiple host tags are NOT supported at server-side. + label: 'label.host.tag', + docID: 'helpComputeOfferingHostTags' + }, + cpuCap: { + label: 'label.CPU.cap', + isBoolean: true, + isChecked: false, + docID: 'helpComputeOfferingCPUCap' + }, + isPublic: { + label: 'label.public', + isBoolean: true, + isReverse: true, + isChecked: false, + docID: 'helpComputeOfferingPublic' + }, + + isVolatile: { + label: 'label.volatile', + isBoolean: true, + isChecked: false + + }, + + deploymentPlanner: { + label: 'label.deployment.planner', + select: function(args) { + if (isAdmin()) { + $.ajax({ + url: createURL('listDeploymentPlanners'), + dataType: 'json', + success: function(json) { + var items = [{ + id: '', + description: '' + }]; + var plannerObjs = json.listdeploymentplannersresponse.deploymentPlanner; + $(plannerObjs).each(function() { + items.push({ + id: this.name, + description: this.name + }); + }); + args.response.success({ + data: items + }); + args.$select.change(function() { + var $form = $(this).closest('form'); + var $fields = $form.find('.field'); + if ($(this).val() == "ImplicitDedicationPlanner") { + $form.find('[rel=plannerMode]').css('display', 'block'); + } else { + $form.find('[rel=plannerMode]').hide(); + } + }); + } + }); + } + } + }, + + // plannerKey:{label:'Planner Key' , docID:'helpImplicitPlannerKey'}, + plannerMode: { + label: 'label.planner.mode', + select: function(args) { + var items = []; + items.push({ + id: '', + description: '' + }); + items.push({ + id: 'Strict', + description: 'Strict' + }); + items.push({ + id: 'Preferred', + description: 'Preferred' + }); + args.response.success({ + data: items + }); + } + }, + + pciDevice: { + label: 'label.gpu', + select: function(args) { + var items = []; + items.push({ + id: '', + description: '' + }); + items.push({ + id: 'Group of NVIDIA Corporation GK107GL [GRID K1] GPUs', + description: 'NVIDIA GRID K1' + }); + items.push({ + id: 'Group of NVIDIA Corporation GK104GL [GRID K2] GPUs', + description: 'NVIDIA GRID K2' + }); + args.response.success({ + data: items + }); + + var vGpuMap = {}; + vGpuMap['Group of NVIDIA Corporation GK107GL [GRID K1] GPUs'] = ['passthrough', 'GRID K100', 'GRID K120Q', 'GRID K140Q', 'GRID K160Q', 'GRID K180Q']; + vGpuMap['Group of NVIDIA Corporation GK104GL [GRID K2] GPUs'] = ['passthrough', 'GRID K200', 'GRID K220Q', 'GRID K240Q', 'GRID K260Q', 'GRID K280Q']; + + args.$select.change(function() { + var gpu = $(this).val(); + + if (gpu == '') { + $(this).closest('form').find('.form-item[rel=\"vgpuType\"]').hide(); + } + else { + $(this).closest('form').find('.form-item[rel=\"vgpuType\"]').css('display', 'inline-block'); + + // enable/disable vGPU type options, depending on selected GPU + var $vGpuTypeSelect = $(this).closest('form').find('select[name=vgpuType]'); + var $vGpuTypeOptions = $vGpuTypeSelect.find('option'); + $vGpuTypeOptions.each(function(index) { + var vGpuTypeOption = $(this).val(); + if (vGpuTypeOption == '' || (gpu in vGpuMap && $.inArray(vGpuTypeOption, vGpuMap[gpu]) > -1)) + $(this).attr('disabled', false); + else + $(this).attr('disabled', true); + }); + + //if selected option is disabled, select the first enabled option instead + if ($vGpuTypeSelect.find('option:selected:disabled').length > 0) { + $vGpuTypeSelect.val($vGpuTypeSelect.find('option:enabled:first').val()); + } + } + }); + } + }, + + vgpuType: { + label: 'label.vgpu.type', + isHidden: true, + select: function(args) { + var items = []; + items.push({ + id: '', + description: '' + }); + items.push({ + id: 'passthrough', + description: 'passthrough' + }); + items.push({ + id: 'GRID K100', + description: 'GRID K100' + }); + items.push({ + id: 'GRID K120Q', + description: 'GRID K120Q' + }); + items.push({ + id: 'GRID K140Q', + description: 'GRID K140Q' + }); + items.push({ + id: 'GRID K160Q', + description: 'GRID K160Q' + }); + items.push({ + id: 'GRID K180Q', + description: 'GRID K180Q' + }); + items.push({ + id: 'GRID K200', + description: 'GRID K200' + }); + items.push({ + id: 'GRID K220Q', + description: 'GRID K220Q' + }); + items.push({ + id: 'GRID K240Q', + description: 'GRID K240Q' + }); + items.push({ + id: 'GRID K260Q', + description: 'GRID K260Q' + }); + items.push({ + id: 'GRID K280Q', + description: 'GRID K280Q' + }); + args.response.success({ + data: items + }); + } + }, + domainId: { + label: 'label.domain', + docID: 'helpComputeOfferingDomain', + dependsOn: 'isPublic', + isMultiple: true, + validation: { + required: true + }, + select: function(args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function(json) { + var items = []; + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + }, + isHidden: true + }, + zoneId: { + label: 'label.zone', + docID: 'helpComputeOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones" + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + + action: function(args) { + var isFixedOfferingType = args.data.offeringType == 'fixed'; + var data = { + issystem: false, + name: args.data.name, + displaytext: args.data.description, + storageType: args.data.storageType, + provisioningType :args.data.provisioningType, + customized: !isFixedOfferingType, + cacheMode: args.data.cacheMode + }; + + //custom fields (begin) + if (isFixedOfferingType) { + $.extend(data, { + cpuNumber: args.data.cpuNumber + }); + $.extend(data, { + cpuSpeed: args.data.cpuSpeed + }); + $.extend(data, { + memory: args.data.memory + }); + } else { + if(args.data.cpuSpeed != null && args.data.minCPUNumber != null && args.data.maxCPUNumber != null && args.data.minMemory != null && args.data.maxMemory != null){ + $.extend(data, { + cpuSpeed: args.data.cpuSpeed + }); + $.extend(data, { + mincpunumber: args.data.minCPUNumber + }); + $.extend(data, { + maxcpunumber: args.data.maxCPUNumber + }); + $.extend(data, { + minmemory: args.data.minMemory + }); + $.extend(data, { + maxmemory: args.data.maxMemory + }); + } + } + //custom fields (end) + + if (args.data.deploymentPlanner != null && args.data.deploymentPlanner.length > 0) { + $.extend(data, { + deploymentplanner: args.data.deploymentPlanner + }); + } + + var array1 = []; + if (args.data.deploymentPlanner == "ImplicitDedicationPlanner" && args.data.plannerMode != "") { + array1.push("&serviceofferingdetails[0].key" + "=" + "ImplicitDedicationMode"); + array1.push("&serviceofferingdetails[0].value" + "=" + args.data.plannerMode); + } + + if (args.data.pciDevice != "") { + array1.push("&serviceofferingdetails[1].key" + "=" + "pciDevice"); + array1.push("&serviceofferingdetails[1].value" + "=" + args.data.pciDevice); + } + + if (args.data.vgpuType != "") { + array1.push("&serviceofferingdetails[2].key" + "=" + "vgpuType"); + array1.push("&serviceofferingdetails[2].value" + "=" + args.data.vgpuType); + } + + if (args.data.networkRate != null && args.data.networkRate.length > 0) { + $.extend(data, { + networkrate: args.data.networkRate + }); + } + + if (args.data.qosType == 'storage') { + var customIops = args.data.isCustomizedIops == "on"; + + $.extend(data, { + customizediops: customIops + }); + + if (!customIops) { + if (args.data.minIops != null && args.data.minIops.length > 0) { + $.extend(data, { + miniops: args.data.minIops + }); + } + + if (args.data.maxIops != null && args.data.maxIops.length > 0) { + $.extend(data, { + maxiops: args.data.maxIops + }); + } + } + + if (args.data.hypervisorSnapshotReserve != null && args.data.hypervisorSnapshotReserve.length > 0) { + $.extend(data, { + hypervisorsnapshotreserve: args.data.hypervisorSnapshotReserve + }); + } + } else if (args.data.qosType == 'hypervisor') { + if (args.data.diskBytesReadRate != null && args.data.diskBytesReadRate.length > 0) { + $.extend(data, { + bytesreadrate: args.data.diskBytesReadRate + }); + } + + if (args.data.diskBytesWriteRate != null && args.data.diskBytesWriteRate.length > 0) { + $.extend(data, { + byteswriterate: args.data.diskBytesWriteRate + }); + } + + if (args.data.diskIopsReadRate != null && args.data.diskIopsReadRate.length > 0) { + $.extend(data, { + iopsreadrate: args.data.diskIopsReadRate + }); + } + + if (args.data.diskIopsWriteRate != null && args.data.diskIopsWriteRate.length > 0) { + $.extend(data, { + iopswriterate: args.data.diskIopsWriteRate + }); + } + } + + $.extend(data, { + offerha: (args.data.offerHA == "on") + }); + + if (args.data.storageTags != null && args.data.storageTags.length > 0) { + $.extend(data, { + tags: args.data.storageTags + }); + } + + if (args.data.hostTags != null && args.data.hostTags.length > 0) { + $.extend(data, { + hosttags: args.data.hostTags + }); + } + + $.extend(data, { + limitcpuuse: (args.data.cpuCap == "on") + }); + + $.extend(data, { + isvolatile: (args.data.isVolatile == "on") + }); + + if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(data, { + domainid: domainId + }); + } + } + + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : undefined; + if (zoneId) { + $.extend(data, { + zoneid: zoneId + }); + } + + $.ajax({ + url: createURL('createServiceOffering' + array1.join("")), + data: data, + success: function(json) { + var item = json.createserviceofferingresponse.serviceoffering; + args.response.success({ + data: item + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + + dataProvider: function(args) { + var data = {}; + listViewDataProvider(args, data); + + $.extend(data, { + issystem: false + }); + + $.ajax({ + url: createURL('listServiceOfferings&isrecursive=true'), + data: data, + success: function(json) { + var items = json.listserviceofferingsresponse.serviceoffering; + args.response.success({ + actionFilter: serviceOfferingActionfilter, + data: items + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + detailView: { + name: 'label.service.offering.details', + actions: { + edit: { + label: 'label.edit', + action: function(args) { + var data = { + id: args.context.serviceOfferings[0].id, + name: args.data.name, + displaytext: args.data.displaytext + }; + $.ajax({ + url: createURL('updateServiceOffering'), + data: data, + success: function(json) { + var item = json.updateserviceofferingresponse.serviceoffering; + args.response.success({ + data: item + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }, + + remove: { + label: 'label.action.delete.service.offering', + messages: { + confirm: function(args) { + return 'message.action.delete.service.offering'; + }, + notification: function(args) { + return 'label.action.delete.service.offering'; + } + }, + action: function(args) { + var data = { + id: args.context.serviceOfferings[0].id + }; + $.ajax({ + url: createURL('deleteServiceOffering'), + data: data, + async: true, + success: function(json) { + args.response.success(); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: function(args) { + args.complete(); + } + } + }, + + updateOfferingAccess: { + label: 'label.action.update.offering.access', + messages: { + notification: function(args) { + return 'label.action.update.offering.access'; + } + }, + createForm: { + title: 'label.compute.offering.access', + desc: '', + preFilter: function(args) { + if (isAdmin()) { + } else { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); + args.$form.find('.form-item[rel=isPublic]').hide(); + args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown + args.$form.find('.form-item[rel=zoneId]').hide(); + } + var formOffering = args.context.serviceOfferings[0]; + $.ajax({ + url: createURL('listServiceOfferings&isrecursive=true'), + data: { + id: args.context.serviceOfferings[0].id + }, + dataType: "json", + async: false, + success: function (json) { + var item = json.listserviceofferingsresponse.serviceoffering[0]; + formOffering = item; + args.response.success({ + data: item + }); + } + }); //end ajax + var offeringDomainIds = formOffering.domainid; + if (offeringDomainIds) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); + args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown + offeringDomainIds = offeringDomainIds.indexOf(",") != -1 ? offeringDomainIds.split(",") : [offeringDomainIds]; + var options = args.$form.find('.form-item[rel=domainId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringDomainIds, function(domainIdIndex, domainId) { + domainId = domainId.toString().trim(); + if ($(option).val() === domainId) { + $(option).attr('selected','selected'); + } + }); + }); + } else { + if (isAdmin()) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', true); + } + } + var offeringZoneIds = formOffering.zoneid; + if (offeringZoneIds) { + offeringZoneIds = offeringZoneIds.indexOf(",") != -1 ? offeringZoneIds.split(",") : [offeringZoneIds]; + var options = args.$form.find('.form-item[rel=zoneId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringZoneIds, function(zoneIdIndex, zoneId) { + zoneId = zoneId.toString().trim(); + if ($(option).val() === zoneId) { + $(option).attr('selected','selected'); + } + }); + }); + } + }, + fields: { + isPublic: { + label: 'label.public', + isBoolean: true, + isReverse: true, + isChecked: false, + docID: 'helpComputeOfferingPublic' + }, + domainId: { + label: 'label.domain', + docID: 'helpComputeOfferingDomain', + dependsOn: 'isPublic', + isMultiple: true, + isHidden: true, + validation: { + required: true + }, + select: function(args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function(json) { + var items = []; + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + var options = args.$form.find('.form-item[rel=domainId]').children('option'); + $.each(options, function() { + console.log($(this).val()); + }); + console.log("Hello! "+options); + } + }); + } + }, + zoneId: { + label: 'label.zone', + docID: 'helpComputeOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones", + selected: true + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + action: function(args) { + var data = { + id: args.context.serviceOfferings[0].id + }; + if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(data, { + domainid: domainId + }); + } + } else { + $.extend(data, { + domainid: "public" + }); + } + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : "all"; + if (zoneId) { + $.extend(data, { + zoneid: zoneId + }); + } + $.ajax({ + url: createURL('updateServiceOffering'), + data: data, + dataType: "json", + async: false, + success: function (json) { + var item = json.updateserviceofferingresponse.serviceoffering; + args.response.success({ + data: item + }); + } + }); //end ajax + }, + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + + tabs: { + details: { + title: 'label.details', + + fields: [{ + name: { + label: 'label.name', + isEditable: true, + validation: { + required: true + } + } + }, { + id: { + label: 'label.id' + }, + displaytext: { + label: 'label.description', + isEditable: true, + validation: { + required: true + } + }, + storagetype: { + label: 'label.storage.type' + }, + provisioningtype: { + label: 'label.disk.provisioningtype' + }, + cacheMode: { + label: 'label.cache.mode' + }, + cpunumber: { + label: 'label.num.cpu.cores' + }, + cpuspeed: { + label: 'label.cpu.mhz', + converter: function(args) { + return cloudStack.converters.convertHz(args); + } + }, + memory: { + label: 'label.memory.mb', + converter: function(args) { + if (args == undefined) + return ''; + else + return cloudStack.converters.convertBytes(args * 1024 * 1024); + } + }, + networkrate: { + label: 'label.network.rate' + }, + iscustomizediops: { + label: 'label.custom.disk.iops', + converter: cloudStack.converters.toBooleanText + }, + miniops: { + label: 'label.disk.iops.min', + converter: function(args) { + if (args > 0) + return args; + else + return "N/A"; + } + }, + maxiops: { + label: 'label.disk.iops.max', + converter: function(args) { + if (args > 0) + return args; + else + return "N/A"; + } + }, + hypervisorsnapshotreserve: { + label: 'label.hypervisor.snapshot.reserve', + converter: function(args) { + if (args > 0) + return args; + else + return "N/A"; + } + }, + diskBytesReadRate: { + label: 'label.disk.bytes.read.rate' + }, + diskBytesWriteRate: { + label: 'label.disk.bytes.write.rate' + }, + diskIopsReadRate: { + label: 'label.disk.iops.read.rate' + }, + diskIopsWriteRate: { + label: 'label.disk.iops.write.rate' + }, + offerha: { + label: 'label.offer.ha', + converter: cloudStack.converters.toBooleanText + }, + limitcpuuse: { + label: 'label.CPU.cap', + converter: cloudStack.converters.toBooleanText + }, + isvolatile: { + label: 'label.volatile', + converter: cloudStack.converters.toBooleanText + }, + deploymentplanner: { + label: 'label.deployment.planner' + }, + plannerMode: { + label: 'label.planner.mode' + }, + pciDevice: { + label: 'label.gpu' + }, + vgpuType: { + label: 'label.vgpu.type' + }, + tags: { + label: 'label.storage.tags' + }, + hosttags: { + label: 'label.host.tag' + }, + domain: { + label: 'label.domain' + }, + zone: { + label: 'label.zone' + }, + created: { + label: 'label.created', + converter: cloudStack.converters.toLocalDate + } + }], + + dataProvider: function(args) { + var data = { + issystem: false, + id: args.context.serviceOfferings[0].id + }; + $.ajax({ + url: createURL('listServiceOfferings&isrecursive=true'), + data: data, + async: true, + success: function(json) { + var item = json.listserviceofferingsresponse.serviceoffering[0]; + + if (item.deploymentplanner != null && item.serviceofferingdetails != null) { + if (item.deploymentplanner == 'ImplicitDedicationPlanner' && item.serviceofferingdetails.ImplicitDedicationMode != null) { + item.plannerMode = item.serviceofferingdetails.ImplicitDedicationMode; + } + } + + if (item.serviceofferingdetails != null) { + item.pciDevice = item.serviceofferingdetails.pciDevice; + item.vgpuType = item.serviceofferingdetails.vgpuType; + } + + args.response.success({ + actionFilter: serviceOfferingActionfilter, + data: item + }); + } + }); + } + } + } + } + } + }, + + systemServiceOfferings: { + type: 'select', + title: 'label.menu.system.service.offerings', + listView: { + id: 'systemServiceOfferings', + label: 'label.menu.system.service.offerings', + fields: { + name: { + label: 'label.name', + editable: true + }, + displaytext: { + label: 'label.description' + } + }, + + reorder: cloudStack.api.actions.sort('updateServiceOffering', 'systemServiceOfferings'), + + actions: { + add: { + label: 'label.add.system.service.offering', + + messages: { + confirm: function(args) { + return 'message.add.system.service.offering'; + }, + notification: function(args) { + return 'label.add.system.service.offering'; + } + }, + + createForm: { + title: 'label.add.system.service.offering', + preFilter: function(args) { + if (isAdmin()) { + } else { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); + args.$form.find('.form-item[rel=isPublic]').hide(); + args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown + } + }, + fields: { + name: { + label: 'label.name', + validation: { + required: true + }, + docID: 'helpSystemOfferingName' + }, + description: { + label: 'label.description', + validation: { + required: true + }, + docID: 'helpSystemOfferingDescription' + }, + systemvmtype: { + label: 'label.system.vm.type', + docID: 'helpSystemOfferingVMType', + select: function(args) { + var items = []; + items.push({ + id: 'domainrouter', + description: _l('label.domain.router') + }); + items.push({ + id: 'consoleproxy', + description: _l('label.console.proxy') + }); + items.push({ + id: 'secondarystoragevm', + description: _l('label.secondary.storage.vm') + }); + args.response.success({ + data: items + }); + } + }, + storageType: { + label: 'label.storage.type', + docID: 'helpSystemOfferingStorageType', + select: function(args) { + var items = []; + items.push({ + id: 'shared', + description: 'shared' + }); + items.push({ + id: 'local', + description: 'local' + }); + args.response.success({ + data: items + }); + } + }, + provisioningType: { + label: 'label.disk.provisioningtype', + docID: 'helpDiskOfferingProvisioningType', + select: function(args) { + var items = []; + items.push({ + id: 'thin', + description: 'thin' + }); + items.push({ + id: 'sparse', + description: 'sparse' + }); + items.push({ + id: 'fat', + description: 'fat' + }); + args.response.success({ + data: items + }); + } + }, + cacheMode: { + label: 'label.cache.mode', + docID: 'helpDiskOfferingCacheMode', + select: function(args) { + var items = []; + items.push({ + id: 'none', + description: 'No disk cache' + }); + items.push({ + id: 'writeback', + description: 'Write-back disk caching' + }); + items.push({ + id: 'writethrough', + description: 'Write-through disk caching' + }); + args.response.success({ + data: items + }) + } + }, + cpuNumber: { + label: 'label.num.cpu.cores', + docID: 'helpSystemOfferingCPUCores', + validation: { + required: true, + number: true + } + }, + cpuSpeed: { + label: 'label.cpu.mhz', + docID: 'helpSystemOfferingCPUMHz', + validation: { + required: true, + number: true + } + }, + memory: { + label: 'label.memory.mb', + docID: 'helpSystemOfferingMemory', + validation: { + required: true, + number: true + } + }, + networkRate: { + label: 'label.network.rate', + docID: 'helpSystemOfferingNetworkRate', + validation: { + required: false, //optional + number: true + } + }, + qosType: { + label: 'label.qos.type', + docID: 'helpDiskOfferingQoSType', + select: function(args) { + var items = []; + items.push({ + id: '', + description: '' + }); + items.push({ + id: 'hypervisor', + description: 'hypervisor' + }); + items.push({ + id: 'storage', + description: 'storage' + }); + args.response.success({ + data: items + }); + + args.$select.change(function() { + var $form = $(this).closest('form'); + var $isCustomizedIops = $form.find('.form-item[rel=isCustomizedIops]'); + var $minIops = $form.find('.form-item[rel=minIops]'); + var $maxIops = $form.find('.form-item[rel=maxIops]'); + var $diskBytesReadRate = $form.find('.form-item[rel=diskBytesReadRate]'); + var $diskBytesWriteRate = $form.find('.form-item[rel=diskBytesWriteRate]'); + var $diskIopsReadRate = $form.find('.form-item[rel=diskIopsReadRate]'); + var $diskIopsWriteRate = $form.find('.form-item[rel=diskIopsWriteRate]'); + + var qosId = $(this).val(); + + if (qosId == 'storage') { // Storage QoS + $diskBytesReadRate.hide(); + $diskBytesWriteRate.hide(); + $diskIopsReadRate.hide(); + $diskIopsWriteRate.hide(); + + $minIops.css('display', 'inline-block'); + $maxIops.css('display', 'inline-block'); + } else if (qosId == 'hypervisor') { // Hypervisor Qos + $minIops.hide(); + $maxIops.hide(); + + $diskBytesReadRate.css('display', 'inline-block'); + $diskBytesWriteRate.css('display', 'inline-block'); + $diskIopsReadRate.css('display', 'inline-block'); + $diskIopsWriteRate.css('display', 'inline-block'); + } else { // No Qos + $diskBytesReadRate.hide(); + $diskBytesWriteRate.hide(); + $diskIopsReadRate.hide(); + $diskIopsWriteRate.hide(); + $minIops.hide(); + $maxIops.hide(); + } + }); + } + }, + minIops: { + label: 'label.disk.iops.min', + docID: 'helpDiskOfferingDiskIopsMin', + validation: { + required: false, + number: true + } + }, + maxIops: { + label: 'label.disk.iops.max', + docID: 'helpDiskOfferingDiskIopsMax', + validation: { + required: false, + number: true + } + }, + diskBytesReadRate: { + label: 'label.disk.bytes.read.rate', + docID: 'helpSystemOfferingDiskBytesReadRate', + validation: { + required: false, //optional + number: true + } + }, + diskBytesWriteRate: { + label: 'label.disk.bytes.write.rate', + docID: 'helpSystemOfferingDiskBytesWriteRate', + validation: { + required: false, //optional + number: true + } + }, + diskIopsReadRate: { + label: 'label.disk.iops.read.rate', + docID: 'helpSystemOfferingDiskIopsReadRate', + validation: { + required: false, //optional + number: true + } + }, + diskIopsWriteRate: { + label: 'label.disk.iops.write.rate', + docID: 'helpSystemOfferingDiskIopsWriteRate', + validation: { + required: false, //optional + number: true + } + }, + offerHA: { + label: 'label.offer.ha', + docID: 'helpSystemOfferingHA', + isBoolean: true, + isChecked: false + }, + storageTags: { + label: 'label.storage.tags', + docID: 'helpSystemOfferingStorageTags' + }, + hostTags: { + label: 'label.host.tags', + docID: 'helpSystemOfferingHostTags' + }, + cpuCap: { + label: 'label.CPU.cap', + isBoolean: true, + isChecked: false, + docID: 'helpSystemOfferingCPUCap' + }, + isPublic: { + label: 'label.public', + isBoolean: true, + isReverse: true, + isChecked: false, + docID: 'helpSystemOfferingPublic' + }, + domainId: { + label: 'label.domain', + docID: 'helpSystemOfferingDomain', + dependsOn: 'isPublic', + select: function(args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function(json) { + var items = []; + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + }, + isHidden: true + } + } + }, + + action: function(args) { + var data = { + issystem: true, + name: args.data.name, + displaytext: args.data.description, + systemvmtype: args.data.systemvmtype, + storageType: args.data.storageType, + provisioningType: args.data.provisioningType, + cpuNumber: args.data.cpuNumber, + cpuSpeed: args.data.cpuSpeed, + memory: args.data.memory, + cacheMode: args.data.cacheMode + }; + + if (args.data.networkRate != null && args.data.networkRate.length > 0) { + $.extend(data, { + networkrate: args.data.networkRate + }); + } + + if (args.data.qosType == 'storage') { + if (args.data.minIops != null && args.data.minIops.length > 0) { + $.extend(data, { + miniops: args.data.minIops + }); + } + + if (args.data.maxIops != null && args.data.maxIops.length > 0) { + $.extend(data, { + maxiops: args.data.maxIops + }); + } + } else if (args.data.qosType == 'hypervisor') { + if (args.data.diskBytesReadRate != null && args.data.diskBytesReadRate.length > 0) { + $.extend(data, { + bytesreadrate: args.data.diskBytesReadRate + }); + } + + if (args.data.diskBytesWriteRate != null && args.data.diskBytesWriteRate.length > 0) { + $.extend(data, { + byteswriterate: args.data.diskBytesWriteRate + }); + } + + if (args.data.diskIopsReadRate != null && args.data.diskIopsReadRate.length > 0) { + $.extend(data, { + iopsreadrate: args.data.diskIopsReadRate + }); + } + + if (args.data.diskIopsWriteRate != null && args.data.diskIopsWriteRate.length > 0) { + $.extend(data, { + iopswriterate: args.data.diskIopsWriteRate + }); + } + } + + $.extend(data, { + offerha: (args.data.offerHA == "on") + }); + + if (args.data.storageTags != null && args.data.storageTags.length > 0) { + $.extend(data, { + tags: args.data.storageTags + }); + } + + if (args.data.hostTags != null && args.data.hostTags.length > 0) { + $.extend(data, { + hosttags: args.data.hostTags + }); + } + + $.extend(data, { + limitcpuuse: (args.data.cpuCap == "on") + }); + + if (args.data.isPublic != "on") { + $.extend(data, { + domainid: args.data.domainId + }); + } + + $.ajax({ + url: createURL('createServiceOffering'), + data: data, + success: function(json) { + var item = json.createserviceofferingresponse.serviceoffering; + args.response.success({ + data: item + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + + dataProvider: function(args) { + var data = {}; + listViewDataProvider(args, data); + + $.extend(data, { + issystem: true + }); + + $.ajax({ + url: createURL('listServiceOfferings&isrecursive=true'), + data: data, + success: function(json) { + var items = json.listserviceofferingsresponse.serviceoffering; + args.response.success({ + data: items + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + detailView: { + name: 'label.system.service.offering.details', + actions: { + edit: { + label: 'label.edit', + action: function(args) { + var data = { + id: args.context.systemServiceOfferings[0].id, + name: args.data.name, + displaytext: args.data.displaytext + }; + $.ajax({ + url: createURL('updateServiceOffering'), + data: data, + success: function(json) { + var item = json.updateserviceofferingresponse.serviceoffering; + args.response.success({ + data: item + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }, + + remove: { + label: 'label.action.delete.system.service.offering', + messages: { + confirm: function(args) { + return 'message.action.delete.system.service.offering'; + }, + notification: function(args) { + return 'label.action.delete.system.service.offering'; + } + }, + action: function(args) { + var data = { + id: args.context.systemServiceOfferings[0].id + }; + $.ajax({ + url: createURL('deleteServiceOffering'), + data: data, + success: function(json) { + args.response.success(); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + + tabs: { + details: { + title: 'label.details', + + fields: [{ + name: { + label: 'label.name', + isEditable: true, + validation: { + required: true + } + } + }, { + id: { + label: 'label.id' + }, + displaytext: { + label: 'label.description', + isEditable: true, + validation: { + required: true + } + }, + systemvmtype: { + label: 'label.system.vm.type', + converter: function(args) { + var text = ''; + switch (args) { + case 'domainrouter': + text = _l('label.domain.router'); + break; + case 'consoleproxy': + text = _l('label.console.proxy'); + break; + case 'secondarystoragevm': + text = _l('label.secondary.storage.vm'); + break; + } + return text; + } + }, + storagetype: { + label: 'label.storage.type' + }, + provisioningtype: { + label: 'label.disk.provisioningtype' + }, + cacheMode: { + label: 'label.cache.mode' + }, + cpunumber: { + label: 'label.num.cpu.cores' + }, + cpuspeed: { + label: 'label.cpu.mhz', + converter: function(args) { + return cloudStack.converters.convertHz(args); + } + }, + memory: { + label: 'label.memory.mb', + converter: function(args) { + if (args == undefined) + return ''; + else + return cloudStack.converters.convertBytes(args * 1024 * 1024); + } + }, + networkrate: { + label: 'label.network.rate' + }, + miniops: { + label: 'label.disk.iops.min', + converter: function(args) { + if (args > 0) + return args; + else + return "N/A"; + } + }, + maxiops: { + label: 'label.disk.iops.max', + converter: function(args) { + if (args > 0) + return args; + else + return "N/A"; + } + }, + diskBytesReadRate: { + label: 'label.disk.bytes.read.rate' + }, + diskBytesWriteRate: { + label: 'label.disk.bytes.write.rate' + }, + diskIopsReadRate: { + label: 'label.disk.iops.read.rate' + }, + diskIopsWriteRate: { + label: 'label.disk.iops.write.rate' + }, + offerha: { + label: 'label.offer.ha', + converter: cloudStack.converters.toBooleanText + }, + limitcpuuse: { + label: 'label.CPU.cap', + converter: cloudStack.converters.toBooleanText + }, + tags: { + label: 'label.storage.tags' + }, + hosttags: { + label: 'label.host.tags' + }, + domain: { + label: 'label.domain' + }, + created: { + label: 'label.created', + converter: cloudStack.converters.toLocalDate + } + }], + + dataProvider: function(args) { + var data = { + issystem: true, + id: args.context.systemServiceOfferings[0].id + }; + $.ajax({ + url: createURL('listServiceOfferings&isrecursive=true'), + data: data, + success: function(json) { + var item = json.listserviceofferingsresponse.serviceoffering[0]; + args.response.success({ + actionFilter: systemServiceOfferingActionfilter, + data: item + }); + } + }); + } + } + } + } + } + }, + + diskOfferings: { + type: 'select', + title: 'label.menu.disk.offerings', + listView: { + id: 'diskOfferings', + label: 'label.menu.disk.offerings', + fields: { + name: { + label: 'label.name' + }, + displaytext: { + label: 'label.description' + }, + iscustomized: { + label: 'label.custom.disk.size', + converter: cloudStack.converters.toBooleanText + }, + disksize: { + label: 'label.disk.size.gb', + converter: function(args) { + if (args != 0) + return args; + else + return "N/A"; + } + } + }, + + reorder: cloudStack.api.actions.sort('updateDiskOffering', 'diskOfferings'), + + dataProvider: function(args) { + var data = {}; + listViewDataProvider(args, data); + var listDiskOfferingsOptions = { + isRecursive: true, + data: data, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }; + var diskOfferings = cloudStack.listDiskOfferings(listDiskOfferingsOptions); + args.response.success({ + data: diskOfferings + }); + }, + + actions: { + add: { + label: 'label.add.disk.offering', + + messages: { + confirm: function(args) { + return 'message.add.disk.offering'; + }, + notification: function(args) { + return 'label.add.disk.offering'; + } + }, + + createForm: { + title: 'label.add.disk.offering', + preFilter: function(args) { + if (isAdmin()) { + } else { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); + args.$form.find('.form-item[rel=isPublic]').hide(); + args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown + args.$form.find('.form-item[rel=tags]').hide(); + } + }, + fields: { + name: { + label: 'label.name', + docID: 'helpDiskOfferingName', + validation: { + required: true + } + }, + description: { + label: 'label.description', + docID: 'helpDiskOfferingDescription', + validation: { + required: true + } + }, + storageType: { + label: 'label.storage.type', + docID: 'helpDiskOfferingStorageType', + select: function(args) { + var items = []; + items.push({ + id: 'shared', + description: 'shared' + }); + items.push({ + id: 'local', + description: 'local' + }); + args.response.success({ + data: items + }); + } + }, + provisioningType: { + label: 'label.disk.provisioningtype', + docID: 'helpDiskOfferingProvisioningType', + select: function(args) { + var items = []; + items.push({ + id: 'thin', + description: 'thin' + }); + items.push({ + id: 'sparse', + description: 'sparse' + }); + items.push({ + id: 'fat', + description: 'fat' + }); + args.response.success({ + data: items + }); + } + }, + isCustomized: { + label: 'label.custom.disk.size', + docID: 'helpDiskOfferingCustomDiskSize', + isBoolean: true, + isReverse: true, + isChecked: false + }, + disksize: { + label: 'label.disk.size.gb', + docID: 'helpDiskOfferingDiskSize', + dependsOn: 'isCustomized', + validation: { + required: true, + number: true + } + }, + qosType: { + label: 'label.qos.type', + docID: 'helpDiskOfferingQoSType', + select: function(args) { + var items = []; + items.push({ + id: '', + description: '' + }); + items.push({ + id: 'hypervisor', + description: 'hypervisor' + }); + items.push({ + id: 'storage', + description: 'storage' + }); + args.response.success({ + data: items + }); + + args.$select.change(function() { + var $form = $(this).closest('form'); + var $isCustomizedIops = $form.find('.form-item[rel=isCustomizedIops]'); + var $minIops = $form.find('.form-item[rel=minIops]'); + var $maxIops = $form.find('.form-item[rel=maxIops]'); + var $hypervisorSnapshotReserve = $form.find('.form-item[rel=hypervisorSnapshotReserve]'); + var $diskBytesReadRate = $form.find('.form-item[rel=diskBytesReadRate]'); + var $diskBytesWriteRate = $form.find('.form-item[rel=diskBytesWriteRate]'); + var $diskIopsReadRate = $form.find('.form-item[rel=diskIopsReadRate]'); + var $diskIopsWriteRate = $form.find('.form-item[rel=diskIopsWriteRate]'); + + var qosId = $(this).val(); + + if (qosId == 'storage') { // Storage QoS + $diskBytesReadRate.hide(); + $diskBytesWriteRate.hide(); + $diskIopsReadRate.hide(); + $diskIopsWriteRate.hide(); + + $isCustomizedIops.css('display', 'inline-block'); + + if ($isCustomizedIops.find('input[type=checkbox]').is(':checked')) { + $minIops.hide(); + $maxIops.hide(); + } else { + $minIops.css('display', 'inline-block'); + $maxIops.css('display', 'inline-block'); + } + + $hypervisorSnapshotReserve.css('display', 'inline-block'); + } else if (qosId == 'hypervisor') { // Hypervisor Qos + $isCustomizedIops.hide(); + $minIops.hide(); + $maxIops.hide(); + $hypervisorSnapshotReserve.hide(); + + $diskBytesReadRate.css('display', 'inline-block'); + $diskBytesWriteRate.css('display', 'inline-block'); + $diskIopsReadRate.css('display', 'inline-block'); + $diskIopsWriteRate.css('display', 'inline-block'); + } else { // No Qos + $diskBytesReadRate.hide(); + $diskBytesWriteRate.hide(); + $diskIopsReadRate.hide(); + $diskIopsWriteRate.hide(); + $isCustomizedIops.hide(); + $minIops.hide(); + $maxIops.hide(); + $hypervisorSnapshotReserve.hide(); + } + }); + } + }, + isCustomizedIops: { + label: 'label.custom.disk.iops', + docID: 'helpDiskOfferingCustomDiskIops', + isBoolean: true, + isReverse: true, + isChecked: false + }, + minIops: { + label: 'label.disk.iops.min', + docID: 'helpDiskOfferingDiskIopsMin', + dependsOn: 'isCustomizedIops', + validation: { + required: false, + number: true + } + }, + maxIops: { + label: 'label.disk.iops.max', + docID: 'helpDiskOfferingDiskIopsMax', + dependsOn: 'isCustomizedIops', + validation: { + required: false, + number: true + } + }, + hypervisorSnapshotReserve: { + label: 'label.hypervisor.snapshot.reserve', + docID: 'helpDiskOfferingHypervisorSnapshotReserve', + validation: { + required: false, + number: true + } + }, + diskBytesReadRate: { + label: 'label.disk.bytes.read.rate', + docID: 'helpDiskOfferingDiskBytesReadRate', + validation: { + required: false, //optional + number: true + } + }, + diskBytesWriteRate: { + label: 'label.disk.bytes.write.rate', + docID: 'helpDiskOfferingDiskBytesWriteRate', + validation: { + required: false, //optional + number: true + } + }, + diskIopsReadRate: { + label: 'label.disk.iops.read.rate', + docID: 'helpDiskOfferingDiskIopsReadRate', + validation: { + required: false, //optional + number: true + } + }, + diskIopsWriteRate: { + label: 'label.disk.iops.write.rate', + docID: 'helpDiskOfferingDiskIopsWriteRate', + validation: { + required: false, //optional + number: true + } + }, + cacheMode: { + label: 'label.cache.mode', + docID: 'helpDiskOfferingCacheMode', + select: function(args) { + var items = []; + items.push({ + id: 'none', + description: 'No disk cache' + }); + items.push({ + id: 'writeback', + description: 'Write-back disk caching' + }); + items.push({ + id: 'writethrough', + description: 'Write-through disk caching' + }); + args.response.success({ + data: items + }); + } + }, + tags: { + label: 'label.storage.tags', + docID: 'helpDiskOfferingStorageTags', + isTokenInput: true, + dataProvider: function(args) { + $.ajax({ + url: createURL("listStorageTags"), + dataType: "json", + success: function(json) { + var item = json.liststoragetagsresponse.storagetag; + var tags = []; + + if (item != null) + { + tags = $.map(item, function(tag) { + return { + id: tag.name, + name: tag.name + }; + }); + } + + args.response.success({ + data: tags, + hintText: _l('hint.type.part.storage.tag'), + noResultsText: _l('hint.no.storage.tags') + }); + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + + args.response.error(errorMsg); + } + }); + } + }, + isPublic: { + label: 'label.public', + isBoolean: true, + isReverse: true, + isChecked: false, + docID: 'helpDiskOfferingPublic' + }, + domainId: { + label: 'label.domain', + docID: 'helpDiskOfferingDomain', + dependsOn: 'isPublic', + isMultiple: true, + validation: { + required: true + }, + select: function(args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function(json) { + var items = []; + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + }, + isHidden: true + }, + zoneId: { + label: 'label.zone', + docID: 'helpDiskOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones" + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + + action: function(args) { + var data = { + isMirrored: false, + name: args.data.name, + displaytext: args.data.description, + storageType: args.data.storageType, + cacheMode: args.data.cacheMode, + provisioningType: args.data.provisioningType, + customized: (args.data.isCustomized == "on") + }; + + if (args.data.isCustomized != "on") { + $.extend(data, { + disksize: args.data.disksize + }); + } + + if (args.data.qosType == 'storage') { + var customIops = args.data.isCustomizedIops == "on"; + + $.extend(data, { + customizediops: customIops + }); + + if (!customIops) { + if (args.data.minIops != null && args.data.minIops.length > 0) { + $.extend(data, { + miniops: args.data.minIops + }); + } + + if (args.data.maxIops != null && args.data.maxIops.length > 0) { + $.extend(data, { + maxiops: args.data.maxIops + }); + } + } + + if (args.data.hypervisorSnapshotReserve != null && args.data.hypervisorSnapshotReserve.length > 0) { + $.extend(data, { + hypervisorsnapshotreserve: args.data.hypervisorSnapshotReserve + }); + } + } else if (args.data.qosType == 'hypervisor') { + if (args.data.diskBytesReadRate != null && args.data.diskBytesReadRate.length > 0) { + $.extend(data, { + bytesreadrate: args.data.diskBytesReadRate + }); + } + + if (args.data.diskBytesWriteRate != null && args.data.diskBytesWriteRate.length > 0) { + $.extend(data, { + byteswriterate: args.data.diskBytesWriteRate + }); + } + + if (args.data.diskIopsReadRate != null && args.data.diskIopsReadRate.length > 0) { + $.extend(data, { + iopsreadrate: args.data.diskIopsReadRate + }); + } + + if (args.data.diskIopsWriteRate != null && args.data.diskIopsWriteRate.length > 0) { + $.extend(data, { + iopswriterate: args.data.diskIopsWriteRate + }); + } + } + + if (args.data.tags != null && args.data.tags.length > 0) { + $.extend(data, { + tags: args.data.tags + }); + } + + if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(data, { + domainid: domainId + }); + } + } + + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : undefined; + if (zoneId) { + $.extend(data, { + zoneid: zoneId + }); + } + + $.ajax({ + url: createURL('createDiskOffering'), + data: data, + success: function(json) { + var item = json.creatediskofferingresponse.diskoffering; + args.response.success({ + data: item + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + + detailView: { + name: 'label.disk.offering.details', + actions: { + edit: { + label: 'label.edit', + action: function(args) { + var data = { + id: args.context.diskOfferings[0].id, + name: args.data.name, + displaytext: args.data.displaytext + }; + $.ajax({ + url: createURL('updateDiskOffering'), + data: data, + success: function(json) { + var item = json.updatediskofferingresponse.diskoffering; + args.response.success({ + data: item + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }, + + remove: { + label: 'label.action.delete.disk.offering', + messages: { + confirm: function(args) { + return 'message.action.delete.disk.offering'; + }, + notification: function(args) { + return 'label.action.delete.disk.offering'; + } + }, + action: function(args) { + var data = { + id: args.context.diskOfferings[0].id + }; + $.ajax({ + url: createURL('deleteDiskOffering'), + data: data, + success: function(json) { + args.response.success(); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: function(args) { + args.complete(); + } + } + }, + + updateOfferingAccess: { + label: 'label.action.update.offering.access', + messages: { + notification: function(args) { + return 'label.action.update.offering.access'; + } + }, + createForm: { + title: 'label.disk.offering.access', + desc: '', + preFilter: function(args) { + if (isAdmin()) { + } else { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); + args.$form.find('.form-item[rel=isPublic]').hide(); + args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown + args.$form.find('.form-item[rel=zoneId]').hide(); + } + var formOffering = args.context.diskOfferings[0]; + $.ajax({ + url: createURL('listDiskOfferings'), + data: { + id: args.context.diskOfferings[0].id + }, + dataType: "json", + async: false, + success: function (json) { + var item = json.listdiskofferingsresponse.diskoffering[0]; + formOffering = item; + args.response.success({ + data: item + }); + } + }); //end ajax + var offeringDomainIds = formOffering.domainid; + if (offeringDomainIds) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); + args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown + offeringDomainIds = offeringDomainIds.indexOf(",") != -1 ? offeringDomainIds.split(",") : [offeringDomainIds]; + var options = args.$form.find('.form-item[rel=domainId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringDomainIds, function(domainIdIndex, domainId) { + domainId = domainId.toString().trim(); + if ($(option).val() === domainId) { + $(option).attr('selected','selected'); + } + }); + }); + } else { + if (isAdmin()) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', true); + } + } + var offeringZoneIds = formOffering.zoneid; + if (offeringZoneIds) { + offeringZoneIds = offeringZoneIds.indexOf(",") != -1 ? offeringZoneIds.split(",") : [offeringZoneIds]; + var options = args.$form.find('.form-item[rel=zoneId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringZoneIds, function(zoneIdIndex, zoneId) { + zoneId = zoneId.toString().trim(); + if ($(option).val() === zoneId) { + $(option).attr('selected','selected'); + } + }); + }); + } + }, + fields: { + isPublic: { + label: 'label.public', + isBoolean: true, + isReverse: true, + isChecked: false, + docID: 'helpDiskOfferingPublic' + }, + domainId: { + label: 'label.domain', + docID: 'helpDiskOfferingDomain', + dependsOn: 'isPublic', + isMultiple: true, + validation: { + required: true + }, + select: function(args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function(json) { + var items = []; + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + }, + isHidden: true + }, + zoneId: { + label: 'label.zone', + docID: 'helpDiskOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones" + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + action: function(args) { + var data = { + id: args.context.diskOfferings[0].id + }; + if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(data, { + domainid: domainId + }); + } + } else { + $.extend(data, { + domainid: "public" + }); + } + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : "all"; + if (zoneId) { + $.extend(data, { + zoneid: zoneId + }); + } + $.ajax({ + url: createURL('updateDiskOffering'), + data: data, + dataType: "json", + async: false, + success: function (json) { + var item = json.updatediskofferingresponse.diskoffering; + args.response.success({ + data: item + }); + } + }); //end ajax + }, + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + + tabs: { + details: { + title: 'label.details', + + fields: [{ + name: { + label: 'label.name', + isEditable: true, + validation: { + required: true + } + } + }, { + id: { + label: 'label.id' + }, + displaytext: { + label: 'label.description', + isEditable: true, + validation: { + required: true + } + }, + iscustomized: { + label: 'label.custom.disk.size', + converter: cloudStack.converters.toBooleanText + }, + disksize: { + label: 'label.disk.size.gb', + converter: function(args) { + if (args != 0) + return args; + else + return "N/A"; + } + }, + iscustomizediops: { + label: 'label.custom.disk.iops', + converter: cloudStack.converters.toBooleanText + }, + miniops: { + label: 'label.disk.iops.min', + converter: function(args) { + if (args > 0) + return args; + else + return "N/A"; + } + }, + maxiops: { + label: 'label.disk.iops.max', + converter: function(args) { + if (args > 0) + return args; + else + return "N/A"; + } + }, + hypervisorsnapshotreserve: { + label: 'label.hypervisor.snapshot.reserve', + converter: function(args) { + if (args > 0) + return args; + else + return "N/A"; + } + }, + diskBytesReadRate: { + label: 'label.disk.bytes.read.rate' + }, + diskBytesWriteRate: { + label: 'label.disk.bytes.write.rate' + }, + diskIopsReadRate: { + label: 'label.disk.iops.read.rate' + }, + diskIopsWriteRate: { + label: 'label.disk.iops.write.rate' + }, + cacheMode: { + label: 'label.cache.mode' + }, + tags: { + label: 'label.storage.tags' + }, + domain: { + label: 'label.domain' + }, + zone: { + label: 'label.zone' + }, + storagetype: { + label: 'label.storage.type' + }, + provisioningtype: { + label: 'label.disk.provisioningtype' + } + }], + + dataProvider: function(args) { + var data = { + isrecursive: true, + id: args.context.diskOfferings[0].id + }; + $.ajax({ + url: createURL('listDiskOfferings'), + dataType: "json", + data: data, + success: function(json) { + var item = json.listdiskofferingsresponse.diskoffering[0]; + args.response.success({ + data: item + }); + } + }); + } + } + } + } + } + }, + + backupOfferings: { + type: 'select', + title: 'label.menu.backup.offerings', + listView: { + id: 'backupOfferings', + label: 'label.menu.backup.offerings', + fields: { + name: { + label: 'label.name', + editable: true + }, + description: { + label: 'label.description' + }, + zonename: { + label: 'label.zone', + } + }, + + actions: { + add: { + label: 'label.import.backup.offering', + createForm: { + title: 'label.import.backup.offering', + fields: { + name: { + label: 'label.name', + validation: { + required: true + } + }, + description: { + label: 'label.description', + validation: { + required: true + } + }, + zoneid: { + label: 'label.zone', + validation: { + required: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: '' + }); + args.response.success({ + data: items + }); + args.$select.change(function() { + var $form = $(this).closest('form'); + var zoneId = $form.find('select#label_zone').val(); + var extSelect = $form.find('select#label_external_id'); + extSelect.empty(); + if (zoneId === -1) { + return; + } + $.ajax({ + url: createURL("listBackupProviderOfferings"), + data: {zoneid: zoneId}, + dataType: "json", + success: function(json) { + var items = []; + var offerings = json.listbackupproviderofferingsresponse.backupoffering; + $(offerings).each(function() { + extSelect.append(new Option(this.name, this.externalid)) + }); + } + }); + }) + } + }); + } + }, + externalid: { + label: 'label.external.id', + select: function(args) { + args.response.success({ + data: [] + }); + } + }, + allowuserdrivenbackups: { + label: 'label.backup.user.driven', + isBoolean: true, + isChecked: true + } + }//end of fields + }, //end of createForm + + action: function(args) { + $.ajax({ + url: createURL('importBackupOffering'), + data: { + name: args.data.name, + description: args.data.description, + zoneid: args.data.zoneid, + externalid: args.data.externalid, + allowuserdrivenbackups: args.data.allowuserdrivenbackups === 'on' + }, + dataType: 'json', + success: function(json) { + var jid = json.importbackupofferingresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function() { + return backupOfferingActionfilter; + } + } + + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + notification: { + poll: pollAsyncJobResult + }, + + messages: { + notification: function(args) { + return 'label.import.backup.offering'; + } + } + } + }, + + dataProvider: function(args) { + var data = {}; + listViewDataProvider(args, data); + + $.ajax({ + url: createURL('listBackupOfferings'), + data: data, + success: function(json) { + var items = json.listbackupofferingsresponse.backupoffering; + args.response.success({ + data: items + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + detailView: { + name: 'label.system.backup.offering.details', + actions: { + remove: { + label: 'label.action.delete.backup.offering', + messages: { + confirm: function(args) { + return 'message.action.delete.backup.offering'; + }, + notification: function(args) { + return 'label.action.delete.backup.offering'; + } + }, + action: function(args) { + var data = { + id: args.context.backupOfferings[0].id + }; + $.ajax({ + url: createURL('deleteBackupOffering'), + data: data, + success: function(json) { + args.response.success(); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + + tabs: { + details: { + title: 'label.details', + + fields: [{ + name: { + label: 'label.name', + isEditable: true, + validation: { + required: true + } + } + }, { + id: { + label: 'label.id' + }, + description: { + label: 'label.description', + isEditable: true, + validation: { + required: true + } + }, + externalid: { + label: 'label.external.id', + }, + allowuserdrivenbackups: { + label: 'label.backup.user.driven' + }, + zoneid: { + label: 'label.zone.id' + }, + created: { + label: 'label.created', + converter: cloudStack.converters.toLocalDate + } + }], + + dataProvider: function(args) { + var data = { + id: args.context.backupOfferings[0].id + }; + $.ajax({ + url: createURL('listBackupOfferings'), + data: data, + success: function(json) { + var item = json.listbackupofferingsresponse.backupoffering[0]; + args.response.success({ + actionFilter: backupOfferingActionfilter, + data: item + }); + } + }); + } + } + } + } + } + }, + + networkOfferings: { + type: 'select', + title: 'label.menu.network.offerings', + listView: { + id: 'networkOfferings', + label: 'label.menu.network.offerings', + fields: { + name: { + label: 'label.name' + }, + state: { + label: 'label.state', + indicator: { + 'Enabled': 'on', + 'Disabled': 'off', + 'Destroyed': 'off' + } + } + }, + + dataProvider: function(args) { + var data = {}; + listViewDataProvider(args, data); + + $.ajax({ + url: createURL('listNetworkOfferings'), + data: data, + success: function(json) { + var items = json.listnetworkofferingsresponse.networkoffering; + + $(items).each(function() { + if (this.availability == "Required") { + requiredNetworkOfferingExists = true; + return false; //break each loop + } + }); + + args.response.success({ + actionFilter: networkOfferingActionfilter, + data: items + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + actions: { + add: { + label: 'label.add.network.offering', + + createForm: { + title: 'label.add.network.offering', + preFilter: function(args) { + var $availability = args.$form.find('.form-item[rel=availability]'); + var $lbType = args.$form.find('.form-item[rel=lbType]'); + var $serviceofferingid = args.$form.find('.form-item[rel=serviceofferingid]'); + var $conservemode = args.$form.find('.form-item[rel=conservemode]'); + var $supportsstrechedl2subnet = args.$form.find('.form-item[rel=supportsstrechedl2subnet]'); + var $supportspublicaccess = args.$form.find('.form-item[rel=supportspublicaccess]'); + var $serviceSourceNatRedundantRouterCapabilityCheckbox = args.$form.find('.form-item[rel="service.SourceNat.redundantRouterCapabilityCheckbox"]'); + var hasAdvancedZones = false; + + // Check whether there are any advanced zones + $.ajax({ + url: createURL('listZones'), + data: {}, + async: false, + success: function(json) { + var zones = json.listzonesresponse.zone; + if (zones != null && zones.length > 0) { + for (var i = 0; i < zones.length; i++) { + if (zones[i].networktype == "Advanced") + hasAdvancedZones = true; + } + } + } + }); + + args.$form.bind('change', function() { //when any field in the dialog is changed + //check whether to show or hide availability field + var $sourceNATField = args.$form.find('input[name=\"service.SourceNat.isEnabled\"]'); + var $guestTypeField = args.$form.find('select[name=guestIpType]'); + + //*** VPC checkbox *** + var $useVpc = args.$form.find('.form-item[rel=\"useVpc\"]'); + var $useVpcCb = $useVpc.find("input[type=checkbox]"); + var $supportedServices = args.$form.find('.form-item[rel=\"supportedServices\"]'); + var $userDataL2 = args.$form.find('.form-item[rel=\"userDataL2\"]'); + if ($guestTypeField.val() == 'Shared') { //Shared network offering + $useVpc.hide(); + $userDataL2.hide(); + $supportedServices.css('display', 'inline-block'); + if ($useVpcCb.is(':checked')) { //if useVpc is checked, + $useVpcCb.prop("checked", false); //remove "checked" attribute in useVpc + } + $conservemode.css('display', 'inline-block'); + } else if ($guestTypeField.val() == 'Isolated') { //Isolated network offering + $useVpc.css('display', 'inline-block'); + $supportedServices.css('display', 'inline-block'); + $userDataL2.hide(); + $conservemode.css('display', 'inline-block'); + } else if ($guestTypeField.val() == 'L2') { + $useVpc.hide(); + $supportedServices.hide(); + $userDataL2.css('display', 'inline-block'); + $conservemode.hide(); + } + var $providers = $useVpcCb.closest('form').find('.dynamic-input select[name!="service.Connectivity.provider"]'); + var $optionsOfProviders = $providers.find('option'); + //p.s. Netscaler is supported in both vpc and non-vpc + if ($useVpc.is(':visible') && $useVpcCb.is(':checked')) { //*** vpc *** + $optionsOfProviders.each(function(index) { + if ($(this).val() == 'InternalLbVm' || $(this).val() == 'VpcVirtualRouter' || $(this).val() == 'Netscaler' || $(this).val() == 'BigSwitchBcf' || $(this).val() == 'ConfigDrive') { + $(this).attr('disabled', false); + } else { + $(this).attr('disabled', true); + } + }); + } else { //*** non-vpc *** + $optionsOfProviders.each(function(index) { + if ($(this).val() == 'InternalLbVm' || $(this).val() == 'VpcVirtualRouter') { + $(this).attr('disabled', true); + } else { + $(this).attr('disabled', false); + } + }); + } + $providers.each(function() { + //if selected option is disabled, select the first enabled option instead + if ($(this).find('option:selected:disabled').length > 0) { + $(this).val($(this).find('option:first')); + } + }); + + + + if (!requiredNetworkOfferingExists && + $sourceNATField.is(':checked') && + $guestTypeField.val() == 'Isolated') { + $availability.css('display', 'inline-block'); + } else { + $availability.hide(); + } + + + //*** LB providers *** + var $lbProvider = args.$form.find('.form-item[rel=\"service.Lb.provider\"]').find('select'); + var $lbProviderOptions = $lbProvider.find('option'); + //when useVpc is checked and service.Lb.isEnabled is checked + if ($useVpcCb.is(':checked') && $("input[name='service.Lb.isEnabled']").is(":checked") == true) { + $lbType.css('display', 'inline-block'); + + if ($lbType.find('select').val() == 'publicLb') { //disable all providers except the ones in lbProviderMap.publicLb.vpc => ["VpcVirtualRouter", "Netscaler"] + for (var i = 0; i < $lbProviderOptions.length; i++) { + var $option = $lbProviderOptions.eq(i); + var supportedProviders = lbProviderMap.publicLb.vpc; + var thisOpionIsSupported = false; + for (var k = 0; k < supportedProviders.length; k++) { + if ($option.val() == supportedProviders[k]) { + thisOpionIsSupported = true; + break; + } + } + if (thisOpionIsSupported == true) { + $option.attr('disabled', false); + } else { + $option.attr('disabled', true); + } + } + } else if ($lbType.find('select').val() == 'internalLb') { //disable all providers except the ones in lbProviderMap.internalLb.vpc => ["InternalLbVm"] + for (var i = 0; i < $lbProviderOptions.length; i++) { + var $option = $lbProviderOptions.eq(i); + var supportedProviders = lbProviderMap.internalLb.vpc; + var thisOpionIsSupported = false; + for (var k = 0; k < supportedProviders.length; k++) { + if ($option.val() == supportedProviders[k]) { + thisOpionIsSupported = true; + break; + } + } + if (thisOpionIsSupported == true) { + $option.attr('disabled', false); + } else { + $option.attr('disabled', true); + } + } + } + + //if selected option is disabled, select the first enabled option instead + if ($lbProvider.find('option:selected:disabled').length > 0) { + $lbProvider.val($lbProvider.find('option:first')); + } + } else { + $lbType.hide(); + } + + //when service(s) has Virtual Router as provider..... + var havingVirtualRouterForAtLeastOneService = false; + $(serviceCheckboxNames).each(function() { + var checkboxName = this; + if ($("input[name='" + checkboxName + "']").is(":checked") == true) { + var providerFieldName = checkboxName.replace(".isEnabled", ".provider"); //either dropdown or input hidden field + var providerName = $("[name='" + providerFieldName + "']").val(); + if (providerName == "VirtualRouter" || providerName == "VpcVirtualRouter") { + havingVirtualRouterForAtLeastOneService = true; + return false; //break each loop + } + } + }); + if (havingVirtualRouterForAtLeastOneService == true) { + $serviceofferingid.css('display', 'inline-block'); + } else { + $serviceofferingid.hide(); + } + + + /* + when service(s) has VPC Virtual Router as provider: + (1) conserve mode is set to unchecked and grayed out. + (2) redundant router capability checkbox is set to unchecked and grayed out. + (3) remove Firewall service, SecurityGroup service. + */ + var havingVpcVirtualRouterForAtLeastOneService = false; + $(serviceCheckboxNames).each(function() { + var checkboxName = this; + if ($("input[name='" + checkboxName + "']").is(":checked") == true) { + var providerFieldName = checkboxName.replace(".isEnabled", ".provider"); //either dropdown or input hidden field + var providerName = $("[name='" + providerFieldName + "']").val(); + if (providerName == "VpcVirtualRouter") { + havingVpcVirtualRouterForAtLeastOneService = true; + return false; //break each loop + } + } + }); + if (havingVpcVirtualRouterForAtLeastOneService == true) { + $conservemode.find("input[type=checkbox]").attr("disabled", "disabled"); + $conservemode.find("input[type=checkbox]").attr('checked', false); + + $serviceSourceNatRedundantRouterCapabilityCheckbox.find("input[type=checkbox]").attr("disabled", "disabled"); + $serviceSourceNatRedundantRouterCapabilityCheckbox.find("input[type=checkbox]").attr('checked', false); + } else { + $serviceSourceNatRedundantRouterCapabilityCheckbox.find("input[type=checkbox]").removeAttr("disabled"); + $conservemode.find("input[type=checkbox]").removeAttr("disabled"); + } + + $('div.ui-dialog').css('top', '24px'); + + //CS-16612 show all services regardless of guestIpType(Shared/Isolated) + /* + //hide/show service fields ***** (begin) ***** + var serviceFieldsToHide = []; + if($guestTypeField.val() == 'Shared') { //Shared network offering + serviceFieldsToHide = [ + 'service.SourceNat.isEnabled', + 'service.PortForwarding.isEnabled', + 'service.Firewall.isEnabled', + 'service.Vpn.isEnabled' + ]; + if(havingVpcVirtualRouterForAtLeastOneService == true) { //add SecurityGroup to to-hide-list + serviceFieldsToHide.push('service.SecurityGroup.isEnabled'); + } + else { //remove SecurityGroup from to-hide-list + var temp = $.map(serviceFieldsToHide, function(item) { + if (item != 'service.SecurityGroup.isEnabled') { + return item; + } + }); + serviceFieldsToHide = temp; + } + } + else { //Isolated network offering + serviceFieldsToHide = [ + 'service.SecurityGroup.isEnabled' + ]; + if(havingVpcVirtualRouterForAtLeastOneService == true) { //add firewall to to-hide-list + serviceFieldsToHide.push('service.Firewall.isEnabled'); + } + else { //remove firewall from to-hide-list + var temp = $.map(serviceFieldsToHide, function(item) { + if (item != 'service.Firewall.isEnabled') { + return item; + } + }); + serviceFieldsToHide = temp; + } + } + */ + + + //CS-16687: NetworkACL should be removed when the guest_type is SHARED + //hide/show service fields ***** (begin) ***** + var serviceFieldsToHide = []; + if ($guestTypeField.val() == 'Shared') { //Shared network offering + serviceFieldsToHide = [ + 'service.NetworkACL.isEnabled' + ]; + } else { //Isolated network offering + serviceFieldsToHide = []; + } + + //hide service fields that are included in serviceFieldsToHide + var $serviceCheckboxesToHide = args.$form.find('.form-item').filter(function() { + if ($.inArray($(this).attr('rel'), serviceFieldsToHide) > -1) { + return true; + } + return false; + }); + $serviceCheckboxesToHide.hide(); + $serviceCheckboxesToHide.find('input[type=checkbox]').attr('checked', false); + + var $serviceProviderDropdownsToHide = args.$form.find('.form-item').filter(function() { + if ($.inArray($(this).attr('depends-on'), serviceFieldsToHide) > -1) { + return true; + } + return false; + }); + $serviceProviderDropdownsToHide.hide(); + + //show service fields that are not included in serviceFieldsToHide + for (var i = 0; i < serviceFields.length; i++) { + var serviceField = serviceFields[i]; + if ($.inArray(serviceField, serviceFieldsToHide) == -1) { + if (args.$form.find('.form-item[rel=\"' + serviceField + '\"]').css('display') == 'none') { + args.$form.find('.form-item[rel=\"' + serviceField + '\"]').css('display', 'inline-block'); + } + } + } + //hide/show service fields ***** (end) ***** + + //show LB InlineMode dropdown only when (1)LB service is checked and LB service provider is F5BigIp (2)Firewall service is checked and Firewall service provider is JuniperSRX + if ((args.$form.find('.form-item[rel=\"service.Lb.isEnabled\"]').find('input[type=checkbox]').is(':checked') == true) && ((args.$form.find('.form-item[rel=\"service.Lb.provider\"]').find('select').val() == 'F5BigIp') || (args.$form.find('.form-item[rel=\"service.Lb.provider\"]').find('select').val() == 'Netscaler')) && + (args.$form.find('.form-item[rel=\"service.Firewall.isEnabled\"]').find('input[type=checkbox]').is(':checked') == true) && (args.$form.find('.form-item[rel=\"service.Firewall.provider\"]').find('select').val() == 'JuniperSRX')) { + args.$form.find('.form-item[rel=\"service.Lb.inlineModeDropdown\"]').css('display', 'inline-block'); + } else { + args.$form.find('.form-item[rel=\"service.Lb.inlineModeDropdown\"]').hide(); + } + + if (args.$form.find('.form-item[rel=\"service.Firewall.isEnabled\"] input[type=checkbox]').is(':checked') == true) { + args.$form.find('.form-item[rel=\"egressdefaultpolicy\"]').css('display', 'inline-block'); + } else { + args.$form.find('.form-item[rel=\"egressdefaultpolicy\"]').css('display', 'none'); + } + + //show Netscaler service packages only when (1)LB Service is checked (2)Service Provider is Netscaler + if ((args.$form.find('.form-item[rel=\"service.Lb.isEnabled\"]').find('input[type=checkbox]').is(':checked') == true) && (args.$form.find('.form-item[rel=\"service.Lb.provider\"]').find('select').val() == 'Netscaler')) { + args.$form.find('.form-item[rel=\"service.Lb.Netscaler.servicePackages\"]').css('display', 'inline-block'); + args.$form.find('.form-item[rel=\"service.Lb.Netscaler.servicePackages.description\"]').css('display', 'inline-block'); + args.$form.find('.form-item[rel=\"service.Lb.Netscaler.servicePackages.description\"]').find("#label_netscaler_service_packages_description").attr("disabled", "disabled"); + args.$form.find('.form-item[rel=\"service.Lb.Netscaler.servicePackages.description\"]').find("#label_netscaler_service_packages_description").text(args.$form.find('.form-item[rel=\"service.Lb.Netscaler.servicePackages\"]').find('#label_netscaler_service_packages option:selected').data("json-obj").desc); + } else { + args.$form.find('.form-item[rel=\"service.Lb.Netscaler.servicePackages\"]').hide(); + args.$form.find('.form-item[rel=\"service.Lb.Netscaler.servicePackages.description\"]').hide(); + args.$form.find('.form-item[rel=\"service.Lb.Netscaler.servicePackages.description\"]').find("#label_netscaler_service_packages_description").attr("disabled", "disabled"); + args.$form.find('.form-item[rel=\"service.Lb.Netscaler.servicePackages.description\"]').find("#label_netscaler_service_packages_description").text(""); + } + + //show Elastic LB checkbox only when (1)LB Service is checked (2)Service Provider is Netscaler (3)Guest IP Type is Shared + if ((args.$form.find('.form-item[rel=\"service.Lb.isEnabled\"]').find('input[type=checkbox]').is(':checked') == true) && (args.$form.find('.form-item[rel=\"service.Lb.provider\"]').find('select').val() == 'Netscaler') && (args.$form.find('.form-item[rel=\"guestIpType\"]').find('select').val() == 'Shared')) { + args.$form.find('.form-item[rel=\"service.Lb.elasticLbCheckbox\"]').css('display', 'inline-block'); + } else { + args.$form.find('.form-item[rel=\"service.Lb.elasticLbCheckbox\"]').hide(); + args.$form.find('.form-item[rel=\"service.Lb.elasticLbCheckbox\"]').find('input[type=checkbox]').attr('checked', false); + } + + //show Elastic IP checkbox only when (1)StaticNat service is checked (2)StaticNat service provider is Netscaler + if ((args.$form.find('.form-item[rel=\"service.StaticNat.isEnabled\"]').find('input[type=checkbox]').is(':checked') == true) && (args.$form.find('.form-item[rel=\"service.StaticNat.provider\"]').find('select').val() == 'Netscaler')) { + args.$form.find('.form-item[rel=\"service.StaticNat.elasticIpCheckbox\"]').css('display', 'inline-block'); + } else { + args.$form.find('.form-item[rel=\"service.StaticNat.elasticIpCheckbox\"]').hide(); + args.$form.find('.form-item[rel=\"service.StaticNat.elasticIpCheckbox\"]').find('input[type=checkbox]').attr('checked', false); + } + + //show Associate Public IP checkbox only when (1)StaticNat Service is checked (2)Service Provider is Netscaler (3)Guest IP Type is Shared (4) Elastic IP checkbox is checked + if ((args.$form.find('.form-item[rel=\"service.StaticNat.isEnabled\"]').find('input[type=checkbox]').is(':checked') == true) && (args.$form.find('.form-item[rel=\"service.StaticNat.provider\"]').find('select').val() == 'Netscaler') && (args.$form.find('.form-item[rel=\"guestIpType\"]').find('select').val() == 'Shared') && (args.$form.find('.form-item[rel=\"service.StaticNat.elasticIpCheckbox\"]').find('input[type=checkbox]').attr('checked') == "checked")) { + args.$form.find('.form-item[rel=\"service.StaticNat.associatePublicIP\"]').css('display', 'inline-block'); + } else { + args.$form.find('.form-item[rel=\"service.StaticNat.associatePublicIP\"]').hide(); + args.$form.find('.form-item[rel=\"service.StaticNat.associatePublicIP\"]').find('input[type=checkbox]').attr('checked', false); + } + + //StretchedL2Subnet checkbox should be displayed only when 'Connectivity' service is checked + if (args.$form.find('.form-item[rel=\"service.Connectivity.isEnabled\"]').find('input[type=checkbox]').is(':checked')) { + $supportsstrechedl2subnet.css('display', 'inline-block'); + } else { + $supportsstrechedl2subnet.hide(); + } + + $supportspublicaccess.hide(); + }); + + args.$form.change(); + }, + fields: { + name: { + label: 'label.name', + validation: { + required: true + }, + docID: 'helpNetworkOfferingName' + }, + + displayText: { + label: 'label.description', + validation: { + required: true + }, + docID: 'helpNetworkOfferingDescription' + }, + + networkRate: { + label: 'label.network.rate', + docID: 'helpNetworkOfferingNetworkRate' + }, + + /* + trafficType: { + label: 'label.traffic.type', validation: { required: true }, + select: function(args) { + args.response.success({ + data: [ + { id: 'GUEST', description: 'Guest' } + ] + }); + } + }, + */ + + guestIpType: { + label: 'label.guest.type', + docID: 'helpNetworkOfferingGuestType', + select: function(args) { + args.response.success({ + data: [{ + id: 'Isolated', + description: 'Isolated' + }, { + id: 'Shared', + description: 'Shared' + }, { + id: 'L2', + description: 'L2' + }] + }); + + args.$select.change(function() { + var $form = $(this).closest("form"); + + if ($(this).val() == "Shared") { + $form.find('.form-item[rel=specifyVlan]').find('input[type=checkbox]').attr("disabled", "disabled"); //make it read-only + $form.find('.form-item[rel=specifyVlan]').find('input[type=checkbox]').attr('checked', true); //make it checked + $form.find('.form-item[rel=isPersistent]').find('input[type=checkbox]').attr("disabled", "disabled"); + + + } else if ($(this).val() == "Isolated" || $(this).val() == "L2") { + $form.find('.form-item[rel=specifyVlan]').find('input[type=checkbox]').removeAttr("disabled"); //make it editable + $form.find('.form-item[rel=isPersistent]').find('input[type=checkbox]').removeAttr("disabled"); + } + }); + } + }, + + isPersistent: { + label: 'label.persistent', + isBoolean: true, + isChecked: false + + }, + + + specifyVlan: { + label: 'label.specify.vlan', + isBoolean: true, + docID: 'helpNetworkOfferingSpecifyVLAN' + }, + + useVpc: { + label: 'label.vpc', + docID: 'helpNetworkOfferingVPC', + isBoolean: true + }, + + useTungsten: { + label: 'label.tungsten', + docID: 'helpNetworkOfferingTungsten', + isBoolean: true + }, + + userDataL2: { + label: 'label.user.data', + docID: 'helpL2UserData', + isBoolean: true, + isHidden: true + }, + + lbType: { //only shown when VPC is checked and LB service is checked + label: 'label.load.balancer.type', + isHidden: true, + select: function(args) { + args.response.success({ + data: [{ + id: 'publicLb', + description: 'Public LB' + }, { + id: 'internalLb', + description: 'Internal LB' + }] + }); + } + }, + + promiscuousMode: { + label: 'label.promiscuous.mode', + select: function(args) { + args.response.success({ + data: [{ + id: '', + description: '' + }, { + id: 'true', + description: 'Accept' + }, { + id: 'false', + description: 'Reject' + }] + }); + } + }, + + macAddressChanges: { + label: 'label.mac.address.changes', + select: function(args) { + args.response.success({ + data: [{ + id: '', + description: '' + }, { + id: 'true', + description: 'Accept' + }, { + id: 'false', + description: 'Reject' + }] + }); + } + }, + + forgedTransmits: { + label: 'label.forged.transmits', + select: function(args) { + args.response.success({ + data: [{ + id: '', + description: '' + }, { + id: 'true', + description: 'Accept' + }, { + id: 'false', + description: 'Reject' + }] + }); + } + }, + + supportedServices: { + label: 'label.supported.services', + + dynamic: function(args) { + $.ajax({ + url: createURL('listSupportedNetworkServices'), + dataType: 'json', + async: true, + success: function(data) { + networkServiceObjs = data.listsupportednetworkservicesresponse.networkservice; + serviceFields = []; + var fields = {}, providerCanenableindividualserviceMap = {}, providerServicesMap = {}, providerDropdownsForciblyChangedTogether = {}; + $(networkServiceObjs).each(function() { + var serviceName = this.name; + var providerObjs = this.provider; + var serviceDisplayName; + + // Sanitize names + switch (serviceName) { + case 'Vpn': + serviceDisplayName = _l('label.vpn'); + break; + case 'Dhcp': + serviceDisplayName = _l('label.dhcp'); + break; + case 'Dns': + serviceDisplayName = _l('label.dns'); + break; + case 'Lb': + serviceDisplayName = _l('label.load.balancer'); + break; + case 'SourceNat': + serviceDisplayName = _l('label.source.nat'); + break; + case 'StaticNat': + serviceDisplayName = _l('label.static.nat'); + break; + case 'PortForwarding': + serviceDisplayName = _l('label.port.forwarding'); + break; + case 'SecurityGroup': + serviceDisplayName = _l('label.security.groups'); + break; + case 'UserData': + serviceDisplayName = _l('label.user.data'); + break; + case 'Connectivity': + serviceDisplayName = _l('label.virtual.networking'); + break; + default: + serviceDisplayName = serviceName; + break; + } + + var id = { + isEnabled: 'service' + '.' + serviceName + '.' + 'isEnabled', + capabilities: 'service' + '.' + serviceName + '.' + 'capabilities', + provider: 'service' + '.' + serviceName + '.' + 'provider' + }; + + serviceCheckboxNames.push(id.isEnabled); + + fields[id.isEnabled] = { + label: serviceDisplayName, + isBoolean: true + }; + serviceFields.push(id.isEnabled); + + if (providerObjs != null && providerObjs.length > 1) { //present provider dropdown when there are multiple providers for a service + fields[id.provider] = { + label: serviceDisplayName + ' Provider', + isHidden: true, + dependsOn: id.isEnabled, + select: function(args) { + //Virtual Router needs to be the first choice in provider dropdown (Bug 12509) + var items = []; + $(providerObjs).each(function() { + if (this.name == "VirtualRouter") + items.unshift({ + id: this.name, + description: this.name + }); + else + items.push({ + id: this.name, + description: this.name + }); + + if (!(this.name in providerCanenableindividualserviceMap)) + providerCanenableindividualserviceMap[this.name] = this.canenableindividualservice; + + if (!(this.name in providerServicesMap)) + providerServicesMap[this.name] = [serviceName]; + else + providerServicesMap[this.name].push(serviceName); + }); + + args.response.success({ + data: items + }); + + // Disable VPC virtual router by default + args.$select.find('option[value=VpcVirtualRouter]').attr('disabled', true); + + args.$select.change(function() { + var $thisProviderDropdown = $(this); + var providerName = $(this).val(); + var canenableindividualservice = providerCanenableindividualserviceMap[providerName]; + if (canenableindividualservice == false) { //This provider can NOT enable individual service, therefore, force all services supported by this provider have this provider selected in provider dropdown + var serviceNames = providerServicesMap[providerName]; + if (serviceNames != null && serviceNames.length > 1) { + providerDropdownsForciblyChangedTogether = {}; //reset + $(serviceNames).each(function() { + var providerDropdownId = 'service' + '.' + this + '.' + 'provider'; + providerDropdownsForciblyChangedTogether[providerDropdownId] = 1; + $("select[name='" + providerDropdownId + "']").val(providerName); + }); + } + } else { //canenableindividualservice == true + if (this.name in providerDropdownsForciblyChangedTogether) { //if this provider dropdown is one of provider dropdowns forcibly changed together earlier, make other forcibly changed provider dropdowns restore default option (i.e. 1st option in dropdown) + for (var key in providerDropdownsForciblyChangedTogether) { + if (key == this.name) + continue; //skip to next item in for loop + else + $("select[name='" + key + "'] option:first").attr("selected", "selected"); + } + providerDropdownsForciblyChangedTogether = {}; //reset + } + } + }); + } + }; + } else if (providerObjs != null && providerObjs.length == 1) { //present hidden field when there is only one provider for a service + fields[id.provider] = { + label: serviceDisplayName + ' Provider', + isHidden: true, + defaultValue: providerObjs[0].name + }; + } + }); + + args.response.success({ + fields: fields + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }, + + //show or hide upon checked services and selected providers above (begin) + serviceofferingid: { + label: 'label.system.offering.for.router', + isHidden: true, + docID: 'helpNetworkOfferingSystemOffering', + select: function(args) { + $.ajax({ + url: createURL('listServiceOfferings&issystem=true&systemvmtype=domainrouter'), + dataType: 'json', + async: true, + success: function(data) { + var serviceOfferings = data.listserviceofferingsresponse.serviceoffering; + + args.response.success({ + data: $.merge( + [{ + id: null, + description: 'None' + }], + $.map(serviceOfferings, function(elem) { + return { + id: elem.id, + description: elem.name + }; + }) + ) + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }, + + "service.SourceNat.redundantRouterCapabilityCheckbox": { + label: 'label.redundant.router.capability', + isHidden: true, + dependsOn: 'service.SourceNat.isEnabled', + docID: 'helpNetworkOfferingRedundantRouterCapability', + isBoolean: true + }, + + "service.SourceNat.sourceNatTypeDropdown": { + label: 'label.supported.source.NAT.type', + isHidden: true, + dependsOn: 'service.SourceNat.isEnabled', + select: function(args) { + args.response.success({ + data: [{ + id: 'peraccount', + description: 'Per account' + }, { + id: 'perzone', + description: 'Per zone' + }] + }); + } + }, + + "service.Lb.elasticLbCheckbox": { + label: "label.elastic.LB", + isHidden: true, + isBoolean: true + }, + + "service.Lb.inlineModeDropdown": { + label: 'label.mode', + docID: 'helpNetworkOfferingMode', + select: function(args) { + var items = []; + items.push({ + id: "false", + description: "side by side" + }); + items.push({ + id: "true", + description: "inline" + }); + args.response.success({ + data: items + }); + } + }, + + "service.Lb.Netscaler.servicePackages": { + label: 'label.netscaler.service.packages', + docID: 'helpNetscalerServicePackages', + isHidden: true, + select: function(args) { + $.ajax({ + url: createURL('listRegisteredServicePackages'), + dataType: 'json', + async: true, + success: function(data) { + var servicePackages = data.listregisteredservicepackage.registeredServicepackage; + + if (servicePackages == undefined || servicePackages == null || !servicePackages) { + servicePackages = data.listregisteredservicepackage; + } + + args.response.success({ + data: $.map(servicePackages, function(elem) { + return { + id: elem.id, + description: elem.name, + desc: elem.description + }; + }) + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }, + + "service.Lb.Netscaler.servicePackages.description": { + label: 'label.netscaler.service.packages.description', + isHidden: true, + isTextarea: true + }, + + "service.Lb.lbIsolationDropdown": { + label: 'label.LB.isolation', + docID: 'helpNetworkOfferingLBIsolation', + isHidden: true, + select: function(args) { + args.response.success({ + data: [{ + id: 'dedicated', + description: 'Dedicated' + }, { + id: 'shared', + description: 'Shared' + }] + }) + } + }, + + "service.StaticNat.elasticIpCheckbox": { + label: "label.elastic.IP", + isHidden: true, + isBoolean: true + }, + + "service.StaticNat.associatePublicIP": { + label: 'label.associate.public.ip', + docID: 'helpNetworkOfferingAssociatePublicIP', + isBoolean: true, + isHidden: true + }, + //show or hide upon checked services and selected providers above (end) + + supportsstrechedl2subnet: { + label: 'label.supportsstrechedl2subnet', + isBoolean: true, + isChecked: false, + isHidden: true + }, + + supportspublicaccess: { + label: 'label.supportspublicaccess', + isBoolean: true, + isChecked: false, + isHidden: true + }, + + conservemode: { + label: 'label.conserve.mode', + isBoolean: true, + isChecked: true, + docID: 'helpNetworkOfferingConserveMode' + }, + + tags: { + label: 'label.tags', + docID: 'helpNetworkOfferingTags' + }, + + availability: { + label: 'label.availability', + isHidden: true, + select: function(args) { + args.response.success({ + data: [{ + id: 'Optional', + description: 'label.optional' + }, { + id: 'Required', + description: 'label.required' + }] + }); + } + }, + + egressdefaultpolicy: { + label: 'label.default.egress.policy', + isHidden: true, + select: function(args) { + args.response.success({ + data: [ + { id: 'ALLOW', description: 'label.allow' }, + { id: 'DENY', description: 'label.deny' } + ] + }); + } + }, + isPublic: { + label: 'label.public', + isBoolean: true, + isReverse: true, + isChecked: false, + docID: 'helpNetworkOfferingPublic' + }, + domainId: { + label: 'label.domain', + docID: 'helpNetworkOfferingDomain', + dependsOn: 'isPublic', + isMultiple: true, + validation: { + required: true + }, + select: function(args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function(json) { + var items = []; + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + }, + isHidden: true + }, + zoneId: { + label: 'label.zone', + docID: 'helpNetworkOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones" + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + + action: function(args) { + var formData = args.data; + var inputData = {}; + var serviceProviderMap = {}; + var serviceCapabilityIndex = 0; + + $.each(formData, function(key, value) { + var serviceData = key.split('.'); + + if (key == 'service.Lb.Netscaler.servicePackages' && value != "") { + inputData['details[' + 0 + '].servicepackageuuid'] = value; + inputData['details[' + 1 + '].servicepackagedescription'] = args.$form.find('#label_netscaler_service_packages option:selected').data().jsonObj.desc; + } + + + if (serviceData.length > 1) { + if (serviceData[0] == 'service' && + serviceData[2] == 'isEnabled' && + value == 'on') { // Services field + + serviceProviderMap[serviceData[1]] = formData[ + 'service.' + serviceData[1] + '.provider' + ]; + } else if ((key == 'service.SourceNat.redundantRouterCapabilityCheckbox') && ("SourceNat" in serviceProviderMap)) { //if checkbox is unchecked, it won't be included in formData in the first place. i.e. it won't fall into this section + inputData['serviceCapabilityList[' + serviceCapabilityIndex + '].service'] = 'SourceNat'; + inputData['serviceCapabilityList[' + serviceCapabilityIndex + '].capabilitytype'] = "RedundantRouter"; + inputData['serviceCapabilityList[' + serviceCapabilityIndex + '].capabilityvalue'] = true; //because this checkbox's value == "on" + serviceCapabilityIndex++; + } else if ((key == 'service.SourceNat.sourceNatTypeDropdown') && ("SourceNat" in serviceProviderMap)) { + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].service'] = 'SourceNat'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilitytype'] = 'SupportedSourceNatTypes'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilityvalue'] = value; + serviceCapabilityIndex++; + } else if ((key == 'service.Lb.elasticLbCheckbox') && ("Lb" in serviceProviderMap)) { //if checkbox is unchecked, it won't be included in formData in the first place. i.e. it won't fall into this section + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].service'] = 'lb'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilitytype'] = 'ElasticLb'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilityvalue'] = true; //because this checkbox's value == "on" + serviceCapabilityIndex++; + } else if ((key == 'service.Lb.inlineModeDropdown') && ("Lb" in serviceProviderMap) && ((serviceProviderMap.Lb == "F5BigIp") || (serviceProviderMap.Lb == "Netscaler"))) { + if (value == 'true') { //CS-16605 do not pass parameter if value is 'false'(side by side) + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].service'] = 'lb'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilitytype'] = 'InlineMode'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilityvalue'] = value; + serviceCapabilityIndex++; + } + } else if ((key == 'service.Lb.lbIsolationDropdown') && ("Lb" in serviceProviderMap)) { + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].service'] = 'lb'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilitytype'] = 'SupportedLbIsolation'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilityvalue'] = value; + serviceCapabilityIndex++; + } else if ((key == 'service.StaticNat.elasticIpCheckbox') && ("StaticNat" in serviceProviderMap)) { //if checkbox is unchecked, it won't be included in formData in the first place. i.e. it won't fall into this section + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].service'] = 'StaticNat'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilitytype'] = 'ElasticIp'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilityvalue'] = true; //because this checkbox's value == "on" + serviceCapabilityIndex++; + } else if ((key == 'service.StaticNat.associatePublicIP') && ("StaticNat" in serviceProviderMap)) { //if checkbox is unchecked, it won't be included in formData in the first place. i.e. it won't fall into this section + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].service'] = 'StaticNat'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilitytype'] = 'associatePublicIP'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilityvalue'] = true; //because this checkbox's value == "on" + serviceCapabilityIndex++; + } else if ((key == 'service.Lb.provider') && ("Lb" in serviceProviderMap) && (serviceProviderMap.Lb == "InternalLbVm")) { + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].service'] = 'lb'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilitytype'] = 'lbSchemes'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilityvalue'] = 'internal'; + serviceCapabilityIndex++; + } + } else if (value != '') { // normal data (serviceData.length ==1), e.g. "name", "displayText", "networkRate", "guestIpType", "lbType" (unwanted), "availability" (unwated when value is "Optional"), "egressdefaultpolicy", "state" (unwanted), "status" (unwanted), "allocationstate" (unwanted) + if (key == "useVpc") { + inputData['forvpc'] = value; + } else if (key == "useTungsten") { + inputData['fortungsten'] = value; + } else if (!(key == "lbType" || (key == "availability" && value == "Optional") || key == "state" || key == "status" || key == "allocationstate" || key == "useVpc" || key == "isPublic" || key == "domainId" || key == "zoneId")) { + inputData[key] = value; + } + } + }); + + for (var key1 in inputData) { + /* When capability ElasticIp=true is passed to API, if capability associatePublicIP is not passed to API, cloudStack API will assume associatePublicIP=true. + So, UI has to explicitly pass associatePublicIP=false to API if its checkbox is unchecked. */ + if (inputData[key1] == 'ElasticIp') { //ElasticIp checkbox is checked + var associatePublicIPExists = false; + for (var key2 in inputData) { + if (inputData[key2] == 'associatePublicIP') { + associatePublicIPExists = true; + break; //break key2 for loop + } + } + if (associatePublicIPExists == false) { //but associatePublicIP checkbox is unchecked + //UI explicitly passes associatePublicIP=false to API + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].service'] = 'StaticNat'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilitytype'] = 'associatePublicIP'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilityvalue'] = false; //associatePublicIP checkbox is unchecked + serviceCapabilityIndex++; + } + break; //break key1 for loop + } + } + + //passing supportsstrechedl2subnet and supportspublicaccess's value as capability + for (var k in inputData) { + if (k == 'supportsstrechedl2subnet' && ("Connectivity" in serviceProviderMap)) { + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].service'] = 'Connectivity'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilitytype'] = 'StretchedL2Subnet'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilityvalue'] = true; + serviceCapabilityIndex++; + } else if (k == 'supportspublicaccess' && ("Connectivity" in serviceProviderMap)) { + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].service'] = 'Connectivity'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilitytype'] = 'PublicAccess'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilityvalue'] = true; + serviceCapabilityIndex++; + } + } + //removing supportsstrechedl2subnet and supportspublicaccess from parameters, it has been set as capability + delete inputData['supportsstrechedl2subnet']; + delete inputData['supportspublicaccess']; + + // Make supported services list + inputData['supportedServices'] = $.map(serviceProviderMap, function(value, key) { + return key; + }).join(','); + + + if (inputData['guestIpType'] == "Shared") { //specifyVlan checkbox is disabled, so inputData won't include specifyVlan + var $specifyVlanCheckbox = args.$form.find('.form-item[rel=specifyVlan]').find('input[type=checkbox]'); + inputData['specifyVlan'] = $specifyVlanCheckbox.is(':checked'); //hardcode inputData['specifyVlan'] + inputData['specifyIpRanges'] = true; + delete inputData.isPersistent; //if Persistent checkbox is unchecked, do not pass isPersistent parameter to API call since we need to keep API call's size as small as possible (p.s. isPersistent is defaulted as false at server-side) + } else if (inputData['guestIpType'] == "Isolated") { //specifyVlan checkbox is shown + //inputData['specifyIpRanges'] = false; + delete inputData.specifyIpRanges; //if specifyIpRanges should be false, do not pass specifyIpRanges parameter to API call since we need to keep API call's size as small as possible (p.s. specifyIpRanges is defaulted as false at server-side) + + if (inputData['specifyVlan'] == 'on') { //specifyVlan checkbox is checked + inputData['specifyVlan'] = true; + } else { //specifyVlan checkbox is unchecked + delete inputData.specifyVlan; //if specifyVlan checkbox is unchecked, do not pass specifyVlan parameter to API call since we need to keep API call's size as small as possible (p.s. specifyVlan is defaulted as false at server-side) + } + + if (inputData['isPersistent'] == 'on') { //It is a persistent network + inputData['isPersistent'] = true; + } else { //Isolated Network with Non-persistent network + delete inputData.isPersistent; //if Persistent checkbox is unchecked, do not pass isPersistent parameter to API call since we need to keep API call's size as small as possible (p.s. isPersistent is defaulted as false at server-side) + } + } else if (inputData['guestIpType'] == "L2") { + if (inputData['specifyVlan'] == 'on') { //specifyVlan checkbox is checked + inputData['specifyVlan'] = true; + } else { //specifyVlan checkbox is unchecked + delete inputData.specifyVlan; //if specifyVlan checkbox is unchecked, do not pass specifyVlan parameter to API call since we need to keep API call's size as small as possible (p.s. specifyVlan is defaulted as false at server-side) + } + + if (inputData['userDataL2'] == 'on') { + inputData['serviceProviderList[0].service'] = 'UserData'; + inputData['serviceProviderList[0].provider'] = 'ConfigDrive'; + inputData['supportedServices'] = 'UserData'; + } else { + delete inputData.serviceProviderList; + } + + //Conserve mode is irrelevant on L2 network offerings as there are no resources to conserve, do not pass it, true by default on server side + delete inputData.conservemode; + } + + if (inputData['forvpc'] == 'on') { + inputData['forvpc'] = true; + } else { + delete inputData.forvpc; //if forVpc checkbox is unchecked, do not pass forVpc parameter to API call since we need to keep API call's size as small as possible (p.s. forVpc is defaulted as false at server-side) + } + + if (inputData['fortungsten'] == 'on') { + inputData['fortungsten'] = true; + } else { + delete inputData.fortungsten; //if forTungsten checkbox is unchecked, do not pass forTungsten parameter to API call since we need to keep API call's size as small as possible (p.s. forTungsten is defaulted as false at server-side) + } + + if (inputData['guestIpType'] == "Shared" || inputData['guestIpType'] == "Isolated") { + if (inputData['conservemode'] == 'on') { + delete inputData.conservemode; //if ConserveMode checkbox is checked, do not pass conservemode parameter to API call since we need to keep API call's size as small as possible (p.s. conservemode is defaulted as true at server-side) + } else { + inputData['conservemode'] = false; + } + } + + // Make service provider map + var serviceProviderIndex = 0; + $.each(serviceProviderMap, function(key, value) { + inputData['serviceProviderList[' + serviceProviderIndex + '].service'] = key; + inputData['serviceProviderList[' + serviceProviderIndex + '].provider'] = value; + serviceProviderIndex++; + }); + + if (args.$form.find('.form-item[rel=egressdefaultpolicy]').is(':visible')) { + if (formData.egressdefaultpolicy === 'ALLOW') { + delete inputData.egressdefaultpolicy; //do not pass egressdefaultpolicy to API call since we need to keep API call's size as small as possible (p.s. egressdefaultpolicy is defaulted as true at server-side) + } else { + inputData['egressdefaultpolicy'] = false; + } + } else { + delete inputData.egressdefaultpolicy; + } + + if ("promiscuousMode" in inputData) { + inputData['details[0].promiscuousMode'] = inputData.promiscuousMode; + delete inputData.promiscuousMode; + } + + if ("macAddressChanges" in inputData) { + inputData['details[0].macAddressChanges'] = inputData.macAddressChanges; + delete inputData.macAddressChanges; + } + + if ("forgedTransmits" in inputData) { + inputData['details[0].forgedTransmits'] = inputData.forgedTransmits; + delete inputData.forgedTransmits; + } + + + if (args.$form.find('.form-item[rel=serviceofferingid]').css("display") == "none") + delete inputData.serviceofferingid; + + if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(inputData, { + domainid: domainId + }); + } + } + + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : undefined; + if (zoneId) { + $.extend(inputData, { + zoneid: zoneId + }); + } + + inputData['traffictype'] = 'GUEST'; //traffic type dropdown has been removed since it has only one option ('Guest'). Hardcode traffic type value here. + + $.ajax({ + url: createURL('createNetworkOffering'), + data: inputData, + type: "POST", //use POST instead of GET since the API call might be overlong and exceed size limit + success: function(data) { + var item = data.createnetworkofferingresponse.networkoffering; + + if (inputData['availability'] == "Required") + requiredNetworkOfferingExists = true; + + args.response.success({ + data: item, + actionFilter: networkOfferingActionfilter + }); + }, + + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + notification: { + poll: function(args) { + args.complete({ + actionFilter: networkOfferingActionfilter + }); + } + }, + + messages: { + notification: function(args) { + return 'label.add.network.offering'; + } + } + } + }, + + reorder: cloudStack.api.actions.sort('updateNetworkOffering', 'networkOfferings'), + + detailView: { + name: 'label.network.offering.details', + actions: { + edit: { + label: 'label.edit', + action: function(args) { + var data = { + id: args.context.networkOfferings[0].id, + name: args.data.name, + displaytext: args.data.displaytext, + availability: args.data.availability + }; + + $.ajax({ + url: createURL('updateNetworkOffering'), + data: data, + success: function(json) { + //if availability is being updated from Required to Optional + if (args.context.networkOfferings[0].availability == "Required" && args.data.availability == "Optional") + requiredNetworkOfferingExists = false; + //if availability is being updated from Optional to Required + if (args.context.networkOfferings[0].availability == "Optional" && args.data.availability == "Required") + requiredNetworkOfferingExists = true; + + var item = json.updatenetworkofferingresponse.networkoffering; + args.response.success({ + data: item + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }, + + enable: { + label: 'label.enable.network.offering', + messages: { + confirm: function(args) { + return 'message.confirm.enable.network.offering'; + }, + notification: function(args) { + return 'message.enabling.network.offering'; + } + }, + action: function(args) { + $.ajax({ + url: createURL("updateNetworkOffering&id=" + args.context.networkOfferings[0].id + "&state=Enabled"), + dataType: "json", + async: true, + success: function(json) { + var item = json.updatenetworkofferingresponse.networkoffering; + args.response.success(); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: function(args) { + args.complete({ + data: { + state: 'Enabled' + } + }); + } + } + }, + + disable: { + label: 'label.disable.network.offering', + messages: { + confirm: function(args) { + return 'message.confirm.disable.network.offering'; + }, + notification: function(args) { + return 'message.disabling.network.offering'; + } + }, + action: function(args) { + $.ajax({ + url: createURL("updateNetworkOffering&id=" + args.context.networkOfferings[0].id + "&state=Disabled"), + dataType: "json", + async: true, + success: function(json) { + var item = json.updatenetworkofferingresponse.networkoffering; + args.response.success(); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: function(args) { + args.complete({ + data: { + state: 'Disabled' + } + }); + } + } + }, + + remove: { + label: 'label.remove.network.offering', + action: function(args) { + $.ajax({ + url: createURL('deleteNetworkOffering'), + data: { + id: args.context.networkOfferings[0].id + }, + success: function(json) { + if (args.context.networkOfferings[0].availability == "Required") + requiredNetworkOfferingExists = false; //since only one or zero Required network offering can exist + + args.response.success(); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + messages: { + confirm: function() { + return 'message.confirm.remove.network.offering'; + }, + notification: function() { + return 'label.remove.network.offering'; + } + }, + notification: { + poll: function(args) { + args.complete({ + data: { + state: 'Destroyed' + }, + actionFilter: networkOfferingActionfilter + }); + } + } + }, + + updateOfferingAccess: { + label: 'label.action.update.offering.access', + messages: { + notification: function(args) { + return 'label.action.update.offering.access'; + } + }, + createForm: { + title: 'label.network.offering.access', + desc: '', + preFilter: function(args) { + var formOffering = args.context.networkOfferings[0]; + $.ajax({ + url: createURL('listNetworkOfferings'), + data: { + id: args.context.networkOfferings[0].id + }, + dataType: "json", + async: false, + success: function (json) { + var item = json.listnetworkofferingsresponse.networkoffering[0]; + formOffering = item; + args.response.success({ + data: item + }); + } + }); //end ajax + var offeringDomainIds = formOffering.domainid; + if (offeringDomainIds) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); + args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown + offeringDomainIds = offeringDomainIds.indexOf(",") != -1 ? offeringDomainIds.split(",") : [offeringDomainIds]; + var options = args.$form.find('.form-item[rel=domainId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringDomainIds, function(domainIdIndex, domainId) { + domainId = domainId.toString().trim(); + if ($(option).val() === domainId) { + $(option).attr('selected','selected'); + } + }); + }); + } else { + if (isAdmin()) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', true); + } + } + var offeringZoneIds = formOffering.zoneid; + if (offeringZoneIds) { + offeringZoneIds = offeringZoneIds.indexOf(",") != -1 ? offeringZoneIds.split(",") : [offeringZoneIds]; + var options = args.$form.find('.form-item[rel=zoneId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringZoneIds, function(zoneIdIndex, zoneId) { + zoneId = zoneId.toString().trim(); + if ($(option).val() === zoneId) { + $(option).attr('selected','selected'); + } + }); + }); + } + }, + fields: { + isPublic: { + label: 'label.public', + isBoolean: true, + isReverse: true, + isChecked: false, + docID: 'helpNetworkOfferingPublic' + }, + domainId: { + label: 'label.domain', + docID: 'helpNetworkOfferingDomain', + dependsOn: 'isPublic', + isMultiple: true, + validation: { + required: true + }, + select: function(args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function(json) { + var items = []; + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + }, + isHidden: true + }, + zoneId: { + label: 'label.zone', + docID: 'helpNetworkOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones" + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + action: function(args) { + var data = { + id: args.context.networkOfferings[0].id + }; + if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(data, { + domainid: domainId + }); + } + } else { + $.extend(data, { + domainid: "public" + }); + } + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : "all"; + if (zoneId) { + $.extend(data, { + zoneid: zoneId + }); + } + $.ajax({ + url: createURL('updateNetworkOffering'), + data: data, + dataType: "json", + async: false, + success: function (json) { + var item = json.updatenetworkofferingresponse.networkoffering; + args.response.success({ + data: item + }); + } + }); //end ajax + }, + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + tabs: { + details: { + title: 'label.details', + + fields: [{ + name: { + label: 'label.name', + isEditable: true, + validation: { + required: true + } + } + }, { + id: { + label: 'label.id' + }, + displaytext: { + label: 'label.description', + isEditable: true, + validation: { + required: true + } + }, + state: { + label: 'label.state' + }, + guestiptype: { + label: 'label.guest.type' + }, + + ispersistent: { + label: 'label.persistent', + converter: cloudStack.converters.toBooleanText + }, + + egressdefaultpolicy: { + label: 'label.egress.default.policy', + converter: function(str) { + return str === true ? 'Allow' : 'Deny'; + } + }, + + availability: { + label: 'label.availability', + isEditable: true, + select: function(args) { + var items = []; + items.push({ + id: 'Required', + description: 'Required' + }); + items.push({ + id: 'Optional', + description: 'Optional' + }); + //items.push({id: 'Unavailable', description: 'Unavailable'}); + args.response.success({ + data: items + }); + } + }, + isdefault: { //created by system by default + label: 'label.created.by.system', + converter: cloudStack.converters.toBooleanText + }, + specifyvlan: { + label: 'label.specify.vlan', + converter: cloudStack.converters.toBooleanText + }, + specifyipranges: { + label: 'label.specify.IP.ranges', + converter: cloudStack.converters.toBooleanText + }, + conservemode: { + label: 'label.conserve.mode', + converter: cloudStack.converters.toBooleanText + }, + networkrate: { + label: 'label.network.rate', + converter: function(args) { + var networkRate = args; + if (args == null || args == -1) { + return "Unlimited"; + } else { + return _s(args) + " Mb/s"; + + } + } + }, + traffictype: { + label: 'label.traffic.type' + }, + supportsstrechedl2subnet: { + label: 'label.supportsstrechedl2subnet', + converter: cloudStack.converters.toBooleanText + }, + supportspublicaccess: { + label: 'label.supportspublicaccess', + converter: cloudStack.converters.toBooleanText + }, + supportedServices: { + label: 'label.supported.services' + }, + serviceCapabilities: { + label: 'label.service.capabilities' + }, + domain: { + label: 'label.domain' + }, + zone: { + label: 'label.zone' + }, + tags: { + label: 'label.tags' + }, + details: { + label: 'label.details' + } + }], + + dataProvider: function(args) { + $.ajax({ + url: createURL('listNetworkOfferings&id=' + args.context.networkOfferings[0].id), + dataType: "json", + async: true, + success: function(json) { + var item = json.listnetworkofferingsresponse.networkoffering[0]; + if (!item.hasOwnProperty('details')) { + item.details = {}; + } + args.response.success({ + actionFilter: networkOfferingActionfilter, + data: $.extend(item, { + details: $.map(item.details, function(val, key) { + return key + "=" + val; + }).join(', '), + + supportedServices: $.map(item.service, function(service) { + return service.name; + }).join(', '), + + serviceCapabilities: $.map(item.service, function(service) { + return service.provider ? $.map(service.provider, function(capability) { + return service.name + ': ' + capability.name; + }).join(', ') : null; + }).join(', ') + }) + }); + } + }); + } + } + } + } + } + }, + + vpcOfferings: { + type: 'select', + title: 'label.menu.vpc.offerings', + listView: { + id: 'vpcOfferings', + label: 'label.menu.vpc.offerings', + fields: { + name: { + label: 'label.name' + }, + state: { + label: 'label.state', + indicator: { + 'Enabled': 'on', + 'Disabled': 'off', + 'Destroyed': 'off' + } + } + }, + + dataProvider: function(args) { + var data = {}; + listViewDataProvider(args, data); + + $.ajax({ + url: createURL('listVPCOfferings'), + data: data, + success: function(json) { + var items = json.listvpcofferingsresponse.vpcoffering; + args.response.success({ + actionFilter: vpcOfferingActionfilter, + data: items + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + actions: { + add: { + label: 'label.add.vpc.offering', + + createForm: { + title: 'label.add.vpc.offering', + + preFilter: function(args) { + var hasAdvancedZones = false; + + // Check whether there are any advanced zones + $.ajax({ + url: createURL('listZones'), + data: {}, + async: false, + success: function(json) { + var zones = json.listzonesresponse.zone; + if (zones != null && zones.length > 0) { + for (var i = 0; i < zones.length; i++) { + if (zones[i].networktype == "Advanced") + hasAdvancedZones = true; + } + } + } + }); + + args.$form.bind('change', function() { //when any field in the dialog is changed + + var $providers = args.$form.find('.dynamic-input select'); + var $optionsOfProviders = $providers.find('option'); + + $providers.each(function() { + //if selected option is disabled, select the first enabled option instead + if ($(this).find('option:selected:disabled').length > 0) { + $(this).val($(this).find('option:first')); + } + }); + }); + + args.$form.change(); + }, + + fields: { + name: { + label: 'label.name', + validation: { + required: true + }, + docID: 'helpVpcOfferingName' + }, + + displayText: { + label: 'label.description', + validation: { + required: true + }, + docID: 'helpVpcOfferingDescription' + }, + + supportedServices: { + label: 'label.supported.services', + + dynamic: function(args) { + var networkServiceObjs = []; + networkServiceObjs.push({ + name: 'Dhcp', + provider: [ + {name: 'VpcVirtualRouter'} + ] + }); + networkServiceObjs.push({ + name: 'Dns', + provider: [{name: 'VpcVirtualRouter'}] + }); + networkServiceObjs.push({ + name: 'Lb', + provider: [ + {name: 'VpcVirtualRouter'}, + {name: 'InternalLbVm'} + ] + }); + networkServiceObjs.push({ + name: 'Gateway', + provider: [{name: 'VpcVirtualRouter'}, + {name: 'BigSwitchBcf'}] + }); + networkServiceObjs.push({ + name: 'StaticNat', + provider: [ + {name: 'VpcVirtualRouter'}, + {name: 'BigSwitchBcf'}] + }); + networkServiceObjs.push({ + name: 'SourceNat', + provider: [ + {name: 'VpcVirtualRouter'}, + {name: 'BigSwitchBcf'}] + }); + networkServiceObjs.push({ + name: 'NetworkACL', + provider: [ + {name: 'VpcVirtualRouter'}, + {name: 'BigSwitchBcf'}] + }); + networkServiceObjs.push({ + name: 'PortForwarding', + provider: [{name: 'VpcVirtualRouter'}] + }); + networkServiceObjs.push({ + name: 'UserData', + provider: [{name: 'VpcVirtualRouter'}, + {name: 'ConfigDrive'}] + }); + networkServiceObjs.push({ + name: 'Vpn', + provider: [{name: 'VpcVirtualRouter'}, + {name: 'BigSwitchBcf'}] + }); + + networkServiceObjs.push({ + name: 'Connectivity', + provider: [ + {name: 'BigSwitchBcf'}, + {name: 'NiciraNvp'}, + {name: 'Ovs'}, + {name: 'JuniperContrailVpcRouter'} + ] + }); + + serviceFields = []; + var fields = {}; + $(networkServiceObjs).each(function() { + var serviceName = this.name; + var providerObjs = this.provider; + var serviceDisplayName; + + // Sanitize names + switch (serviceName) { + case 'Vpn': + serviceDisplayName = _l('label.vpn'); + break; + case 'Dhcp': + serviceDisplayName = _l('label.dhcp'); + break; + case 'Dns': + serviceDisplayName = _l('label.dns'); + break; + case 'Lb': + serviceDisplayName = _l('label.load.balancer'); + break; + case 'SourceNat': + serviceDisplayName = _l('label.source.nat'); + break; + case 'StaticNat': + serviceDisplayName = _l('label.static.nat'); + break; + case 'PortForwarding': + serviceDisplayName = _l('label.port.forwarding'); + break; + case 'UserData': + serviceDisplayName = _l('label.user.data'); + break; + default: + serviceDisplayName = serviceName; + break; + } + + var id = { + isEnabled: 'service' + '.' + serviceName + '.' + 'isEnabled', + capabilities: 'service' + '.' + serviceName + '.' + 'capabilities', + provider: 'service' + '.' + serviceName + '.' + 'provider' + }; + + serviceCheckboxNames.push(id.isEnabled); + + fields[id.isEnabled] = { + label: serviceDisplayName, + isBoolean: true + }; + + serviceFields.push(id.isEnabled); + + fields[id.provider] = { + label: serviceDisplayName + ' Provider', + isHidden: true, + dependsOn: id.isEnabled, + select: function(args) { + var items = []; + $(providerObjs).each(function() { + items.push({ + id: this.name, + description: this.name + }); + }); + args.response.success({ + data: items + }); + } + } + }); + + args.response.success({ + fields: fields + }); + } + }, //end of supportedservices field + + "service.Connectivity.regionLevelVpcCapabilityCheckbox": { + label: 'label.regionlevelvpc', + isHidden: true, + dependsOn: 'service.Connectivity.isEnabled', + isBoolean: true + }, + + "service.Connectivity.distributedRouterCapabilityCheckbox": { + label: 'label.distributedrouter', + isHidden: true, + dependsOn: 'service.Connectivity.isEnabled', + isBoolean: true + }, + + "service.SourceNat.redundantRouterCapabilityCheckbox": { + label: 'label.redundant.router.capability', + isHidden: true, + dependsOn: 'service.SourceNat.isEnabled', + isBoolean: true + }, + isPublic: { + label: 'label.public', + isBoolean: true, + isReverse: true, + isChecked: false, + docID: 'helpVpcOfferingPublic' + }, + domainId: { + label: 'label.domain', + docID: 'helpVpcOfferingDomain', + dependsOn: 'isPublic', + isMultiple: true, + validation: { + required: true + }, + select: function(args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function(json) { + var items = []; + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + }, + isHidden: true + }, + zoneId: { + label: 'label.zone', + docID: 'helpVpcOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones" + }); + args.response.success({ + data: items + }); + } + }); + } + } + }//end of fields + }, //end of createForm + + action: function(args) { + var formData = args.data; + var inputData = {}; + var serviceProviderMap = {}; + var serviceCapabilityIndex = 0; + var excludedKeys = ['isPublic', 'domainId', 'zoneId', 'state', 'status', 'allocationstate'] + $.each(formData, function(key, value) { + var serviceData = key.split('.'); + if (serviceData.length > 1) { + if (serviceData[0] == 'service' && + serviceData[2] == 'isEnabled' && + value == 'on') { // Services field + + serviceProviderMap[serviceData[1]] = formData[ + 'service.' + serviceData[1] + '.provider' + ]; + } else if ((key == 'service.Connectivity.regionLevelVpcCapabilityCheckbox') && ("Connectivity" in serviceProviderMap)) { + inputData['serviceCapabilityList[' + serviceCapabilityIndex + '].service'] = 'Connectivity'; + inputData['serviceCapabilityList[' + serviceCapabilityIndex + '].capabilitytype'] = "RegionLevelVpc"; + inputData['serviceCapabilityList[' + serviceCapabilityIndex + '].capabilityvalue'] = true; + serviceCapabilityIndex++; + } else if ((key == 'service.Connectivity.distributedRouterCapabilityCheckbox') && ("Connectivity" in serviceProviderMap)) { + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].service'] = 'Connectivity'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilitytype'] = 'DistributedRouter'; + inputData['servicecapabilitylist[' + serviceCapabilityIndex + '].capabilityvalue'] = true; + serviceCapabilityIndex++; + } else if ((key == 'service.SourceNat.redundantRouterCapabilityCheckbox') && ("SourceNat" in serviceProviderMap)) { + inputData['serviceCapabilityList[' + serviceCapabilityIndex + '].service'] = 'SourceNat'; + inputData['serviceCapabilityList[' + serviceCapabilityIndex + '].capabilitytype'] = "RedundantRouter"; + inputData['serviceCapabilityList[' + serviceCapabilityIndex + '].capabilityvalue'] = true; + serviceCapabilityIndex++; + } + + } else if (value != '' && $.inArray(key, excludedKeys) == -1) { // Normal data + inputData[key] = value; + } + }); + + // Make supported services list + inputData['supportedServices'] = $.map(serviceProviderMap, function(value, key) { + return key; + }).join(','); + + + // Make service provider map + var serviceProviderIndex = 0; + $.each(serviceProviderMap, function(key, value) { + inputData['serviceProviderList[' + serviceProviderIndex + '].service'] = key; + inputData['serviceProviderList[' + serviceProviderIndex + '].provider'] = value; + serviceProviderIndex++; + }); + + if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(inputData, { + domainid: domainId + }); + } + } + + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : undefined; + if (zoneId) { + $.extend(inputData, { + zoneid: zoneId + }); + } + + $.ajax({ + url: createURL('createVPCOffering'), + data: inputData, + dataType: 'json', + async: true, + success: function(data) { + var item = data.createvpcofferingresponse; + + args.response.success({ + data: item, + actionFilter: vpcOfferingActionfilter + }); + }, + + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + notification: { + poll: function(args) { + args.complete({ + actionFilter: vpcOfferingActionfilter + }); + } + }, + + messages: { + notification: function(args) { + return 'message.added.vpc.offering'; + } + } + } + }, + + reorder: cloudStack.api.actions.sort('updateVPCOffering', 'vpcOfferings'), + + detailView: { + name: 'label.vpc.offering.details', + actions: { + edit: { + label: 'label.edit', + action: function(args) { + var data = { + id: args.context.vpcOfferings[0].id, + name: args.data.name, + displaytext: args.data.displaytext, + availability: args.data.availability + }; + + $.ajax({ + url: createURL('updateVPCOffering'), + data: data, + success: function(json) { + var item = json.updatevpcofferingresponse.vpcoffering; + args.response.success({ + data: item + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }, + + enable: { + label: 'label.enable.vpc.offering', + messages: { + confirm: function(args) { + return 'message.confirm.enable.vpc.offering'; + }, + notification: function(args) { + return 'message.enabling.vpc.offering'; + } + }, + action: function(args) { + $.ajax({ + url: createURL("updateVPCOffering&id=" + args.context.vpcOfferings[0].id + "&state=Enabled"), + dataType: "json", + async: true, + success: function(json) { + var item = json.updatevpcofferingresponse.vpcoffering; + args.response.success(); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: function(args) { + args.complete({ + data: { + state: 'Enabled' + } + }); + } + } + }, + + disable: { + label: 'label.disable.vpc.offering', + messages: { + confirm: function(args) { + return 'message.confirm.disable.vpc.offering'; + }, + notification: function(args) { + return 'message.disabling.vpc.offering'; + } + }, + action: function(args) { + $.ajax({ + url: createURL("updateVPCOffering&id=" + args.context.vpcOfferings[0].id + "&state=Disabled"), + dataType: "json", + async: true, + success: function(json) { + var item = json.updatevpcofferingresponse.vpcoffering; + args.response.success(); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: function(args) { + args.complete({ + data: { + state: 'Disabled' + } + }); + } + } + }, + + remove: { + label: 'label.remove.vpc.offering', + action: function(args) { + $.ajax({ + url: createURL('deleteVPCOffering'), + data: { + id: args.context.vpcOfferings[0].id + }, + success: function(json) { + var jid = json.deletevpcofferingresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function() { + return vpcOfferingActionfilter; + } + } + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + messages: { + confirm: function() { + return 'message.confirm.remove.vpc.offering'; + }, + notification: function() { + return 'label.remove.vpc.offering'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + updateOfferingAccess: { + label: 'label.action.update.offering.access', + messages: { + notification: function(args) { + return 'label.action.update.offering.access'; + } + }, + createForm: { + title: 'label.vpc.offering.access', + desc: '', + preFilter: function(args) { + var formOffering = args.context.vpcOfferings[0]; + $.ajax({ + url: createURL('listVPCOfferings'), + data: { + id: args.context.vpcOfferings[0].id + }, + dataType: "json", + async: false, + success: function (json) { + var item = json.listvpcofferingsresponse.vpcoffering[0]; + formOffering = item; + args.response.success({ + data: item + }); + } + }); //end ajax + var offeringDomainIds = formOffering.domainid; + if (offeringDomainIds) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', false); + args.$form.find('.form-item[rel=domainId]').css('display', 'inline-block'); //shown + offeringDomainIds = offeringDomainIds.indexOf(",") != -1 ? offeringDomainIds.split(",") : [offeringDomainIds]; + var options = args.$form.find('.form-item[rel=domainId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringDomainIds, function(domainIdIndex, domainId) { + domainId = domainId.toString().trim(); + if ($(option).val() === domainId) { + $(option).attr('selected','selected'); + } + }); + }); + } else { + if (isAdmin()) { + args.$form.find('.form-item[rel=isPublic]').find('input[name=isPublic]').prop('checked', true); + } + } + var offeringZoneIds = formOffering.zoneid; + if (offeringZoneIds) { + offeringZoneIds = offeringZoneIds.indexOf(",") != -1 ? offeringZoneIds.split(",") : [offeringZoneIds]; + var options = args.$form.find('.form-item[rel=zoneId]').find('option'); + $.each(options, function(optionIndex, option) { + $.each(offeringZoneIds, function(zoneIdIndex, zoneId) { + zoneId = zoneId.toString().trim(); + if ($(option).val() === zoneId) { + $(option).attr('selected','selected'); + } + }); + }); + } + }, + fields: { + isPublic: { + label: 'label.public', + isBoolean: true, + isReverse: true, + isChecked: false, + docID: 'helpVpcOfferingPublic' + }, + domainId: { + label: 'label.domain', + docID: 'helpVpcOfferingDomain', + dependsOn: 'isPublic', + isMultiple: true, + validation: { + required: true + }, + select: function(args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function(json) { + var items = []; + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + }, + isHidden: true + }, + zoneId: { + label: 'label.zone', + docID: 'helpVpcOfferingZone', + isMultiple: true, + validation: { + allzonesonly: true + }, + select: function(args) { + $.ajax({ + url: createURL("listZones"), + data: {available: 'true'}, + dataType: "json", + async: true, + success: function(json) { + var items = []; + var zoneObjs = json.listzonesresponse.zone; + $(zoneObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + items.unshift({ + id: -1, + description: "All Zones" + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + action: function(args) { + var data = { + id: args.context.vpcOfferings[0].id + }; + if (args.data.isPublic != "on") { + var domainId = (args.data.domainId && Array.isArray(args.data.domainId)) ? args.data.domainId.join(',') : args.data.domainId; + if (domainId) { + $.extend(data, { + domainid: domainId + }); + } + } else { + $.extend(data, { + domainid: "public" + }); + } + var zoneId = (args.data.zoneId && Array.isArray(args.data.zoneId)) ? args.data.zoneId.join(',') : args.data.zoneId != -1 ? args.data.zoneId : "all"; + if (zoneId) { + $.extend(data, { + zoneid: zoneId + }); + } + $.ajax({ + url: createURL('updateVPCOffering'), + data: data, + dataType: "json", + async: false, + success: function (json) { + var item = json.updatevpcofferingresponse.vpcoffering; + args.response.success({ + data: item + }); + } + }); //end ajax + }, + notification: { + poll: function(args) { + args.complete(); + } + } + } + }, + tabs: { + details: { + title: 'label.details', + + fields: [{ + name: { + label: 'label.name', + isEditable: true, + validation: { + required: true + } + } + }, { + id: { + label: 'label.id' + }, + displaytext: { + label: 'label.description', + isEditable: true, + validation: { + required: true + } + }, + state: { + label: 'label.state' + }, + + isdefault: { //created by system by default + label: 'label.created.by.system', + converter: cloudStack.converters.toBooleanText + }, + + supportedServices: { + label: 'label.supported.services' + }, + serviceCapabilities: { + label: 'label.service.capabilities' + }, + distributedvpcrouter: { + label: 'label.vpc.distributedvpcrouter', + converter: cloudStack.converters.toBooleanText + }, + supportsregionLevelvpc: { + label: 'label.vpc.supportsregionlevelvpc', + converter: cloudStack.converters.toBooleanText + }, + serviceCapabilities: { + label: 'label.service.capabilities' + }, + domain: { + label: 'label.domain' + }, + zone: { + label: 'label.zone' + }, + tags: { + label: 'label.tags' + } + + }], + + dataProvider: function(args) { + $.ajax({ + url: createURL('listVPCOfferings&id=' + args.context.vpcOfferings[0].id), + dataType: "json", + async: true, + success: function(json) { + var item = json.listvpcofferingsresponse.vpcoffering[0]; + args.response.success({ + actionFilter: vpcOfferingActionfilter, + data: $.extend(item, { + supportedServices: $.map(item.service, function(service) { + return service.name; + }).join(', '), + + serviceCapabilities: $.map(item.service, function(service) { + return service.provider ? $.map(service.provider, function(capability) { + return service.name + ': ' + capability.name; + }).join(', ') : null; + }).join(', ') + }) + }); + } + }); + } + } + } + } + } + } + } + } + + + var serviceOfferingActionfilter = function(args) { + var jsonObj = args.context.item; + var allowedActions = []; + allowedActions.push("edit"); + allowedActions.push("remove"); + allowedActions.push("updateOfferingAccess"); + return allowedActions; + }; + + var systemServiceOfferingActionfilter = function(args) { + var jsonObj = args.context.item; + var allowedActions = []; + allowedActions.push("edit"); + allowedActions.push("remove"); + return allowedActions; + }; + + var backupOfferingActionfilter = function(args) { + var jsonObj = args.context.item; + var allowedActions = []; + allowedActions.push("remove"); + return allowedActions; + }; + + var diskOfferingActionfilter = function(args) { + var jsonObj = args.context.item; + var allowedActions = []; + allowedActions.push("edit"); + allowedActions.push("remove"); + allowedActions.push("updateOfferingAccess"); + return allowedActions; + }; + + var networkOfferingActionfilter = function(args) { + var jsonObj = args.context.item; + + if (jsonObj.state == 'Destroyed') + return []; + + var allowedActions = []; + allowedActions.push("edit"); + + if (jsonObj.state == "Enabled") + allowedActions.push("disable"); + else if (jsonObj.state == "Disabled") + allowedActions.push("enable"); + + if (jsonObj.isdefault == false) + allowedActions.push("remove"); + allowedActions.push("updateOfferingAccess"); + + return allowedActions; + }; + + var vpcOfferingActionfilter = function(args) { + var jsonObj = args.context.item; + + if (jsonObj.state == 'Destroyed') + return []; + + var allowedActions = []; + allowedActions.push("edit"); + + if (jsonObj.state == "Enabled") + allowedActions.push("disable"); + else if (jsonObj.state == "Disabled") + allowedActions.push("enable"); + + if (jsonObj.isdefault == false) + allowedActions.push("remove"); + allowedActions.push("updateOfferingAccess"); + + return allowedActions; + }; + +})(cloudStack, jQuery); diff --git a/ui/scripts/docs.js b/ui/scripts/docs.js new file mode 100755 index 000000000000..c42a8533ce1e --- /dev/null +++ b/ui/scripts/docs.js @@ -0,0 +1,1417 @@ +// 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. +cloudStack.docs = { + + //Dedicate Resource + + helpDedicateResource: { + + desc: 'Check this box to dedicate the resources to specific domain/account', + externalLink: '' + + }, + + helpAccountForDedication: { + + desc: 'Please enter an account name which belongs to the above selected domain in order to dedicate this resource to this account', + externalLink: '' + + }, + + + //Delete/archive events + helpEventsDeleteType: { + + desc: 'Delete all the events by specifying its TYPE (e.g., USER.LOGIN)', + externalLink: '' + + }, + + helpEventsDeleteDate: { + + desc: 'Delete all the events which have been created in date range (specify start and end date)', + externalLink: '' + }, + + helpEventsArchiveType: { + + desc: 'Archive all the events by specifying its TYPE (i.e., USER.LOGIN)', + externalLink: '' + }, + + helpEventsArchiveDate: { + + desc: 'Archive all the events which have been created in date range (specify start and end date)', + externalLink: '' + }, + + //Delete/archive Alerts + helpAlertsDeleteType: { + + desc: 'Delete all the alerts by specifying its TYPE (integer number)', + externalLink: '' + + }, + + helpAlertsDeleteDate: { + + desc: 'Delete all the alerts which have been created in date range (specify start and end date)', + externalLink: '' + }, + + helpAlertsArchiveType: { + + desc: 'Archive all the alerts by specifying its TYPE (integer number)', + externalLink: '' + }, + + helpAlertsArchiveDate: { + + desc: 'Archive all the alerts which have been created in date range (specify start and end date)', + externalLink: '' + }, + + helpManaged: { + + desc: 'True if CloudStack manages the storage; else, false (check with storage provider if unknown)', + externalLink: '' + }, + + helpCapacityBytes: { + + desc: 'Number of bytes for the primary storage to have', + externalLink: '' + }, + + helpCapacityIops: { + + desc: 'Number of IOPS for the primary storage to have', + externalLink: '' + }, + + helpUrl: { + + desc: 'Arbitrary data to be sent to the storage provider for configuration purposes', + externalLink: '' + }, + + //Ldap + helpLdapUserFilter: { + desc: 'Filter to apply to listing of ldap accounts\n\t"NoFilter": no filtering is done\n\t"LocalDomain": shows only users not in the current or requested domain\n\t"AnyDomain": shows only users not currently known to cloudstack (in any domain)\n\t"PotentialImport": shows all users that (would be) automatically imported to cloudstack with their current usersource', + externalLink: '' + }, + + helpLdapQueryFilter: { + + desc: 'Query filter is used to find a mapped user in the external LDAP server.Cloudstack provides some wildchars to represent the unique attributes in its database . Example - If Cloudstack account-name is same as the LDAP uid, then following will be a valid filter: Queryfilter : (&(uid=%u) , Queryfilter: .incase of Active Directory , Email _ID :(&(mail=%e)) , displayName :(&(displayName=%u)', + + externalLink: '' + }, + + + //IP Reservation tooltips + helpIPReservationCidr: { + desc: 'Edit CIDR when you want to configure IP Reservation in isolated guest Network', + externalLink: '' + + }, + + helpIPReservationNetworkCidr: { + desc: 'The CIDR of the entire network when IP reservation is configured', + externalLink: '' + + }, + + helpReservedIPRange: { + desc: 'The IP Range which is not used by CloudStack to allocate to Guest VMs.Can be used for Non Cloudstack purposes.', + externalLink: '' + }, + + // Add account + helpAccountUsername: { + desc: 'Any desired login ID. Must be unique in the current domain. The same username can exist in other domains, including sub-domains.', + externalLink: '' + }, + + helpOverridePublicNetwork: { + desc: 'Choose to override zone wide traffic label for guest traffic for this cluster', + externalLink: '' + + }, + + helpOverrideGuestNetwork: { + + desc: 'Choose to override zone wide traffic label for guest traffic for this cluster', + externalLink: '' + + }, + + helpAccountPassword: { + desc: 'Any desired password', + externalLink: '' + }, + helpAccountConfirmPassword: { + desc: 'Type the same password again', + externalLink: '' + }, + helpAccountEmail: { + desc: 'The account\'s email address', + externalLink: '' + }, + helpAccountFirstName: { + desc: 'The first name, also known as the given name, of a person; or the first part of the entity represented by the account, such as a customer or department', + externalLink: '' + }, + helpAccountLastName: { + desc: 'The last name, also known as the family name, of a person; or the second part of the name of a customer or department', + externalLink: '' + }, + helpAccountDomain: { + desc: 'Domain in which the account is to be created', + externalLink: '' + }, + helpAccountAccount: { + desc: 'Multiple users can exist in an account. Set the parent account name here.', + externalLink: '' + }, + helpAccountType: { + desc: 'Root admin can access all resources. Domain admin can access the domain\'s users, but not physical servers. User sees only their own resources, such as VMs.', + externalLink: '' + }, + helpAccountTimezone: { + desc: 'Set the time zone that corresponds to the account\'s locale', + externalLink: '' + }, + helpAccountNetworkDomain: { + desc: 'If you want to assign a special domain name to the account\'s guest VM network, specify the DNS suffix', + externalLink: '' + }, + // Add cluster + helpClusterZone: { + desc: 'The zone in which you want to create the cluster', + externalLink: '' + }, + helpClusterHypervisor: { + desc: 'The type of hypervisor software that runs on the hosts in this cluster. All hosts in a cluster run the same hypervisor.', + externalLink: '' + }, + helpClusterPod: { + desc: 'The pod in which you want to create the cluster', + externalLink: '' + }, + helpClusterName: { + desc: 'Cluster name. Used for display only. For VMware hypervisor, this must be a predefined name in VCenter.', + externalLink: '' + }, + helpClustervCenterHost: { + desc: 'The hostname or IP address of the vCenter server', + externalLink: '' + }, + helpClustervCenterUsername: { + desc: 'ID of a user with all administrative privileges on vCenter', + externalLink: '' + }, + helpClustervCenterPassword: { + desc: 'Password of the user in Username', + externalLink: '' + }, + helpClustervCenterDatacenter: { + desc: 'The vCenter datacenter that the cluster is in. For example, cloud.dc.VM', + externalLink: '' + }, + // Add compute offering + helpComputeOfferingName: { + desc: 'Any desired name for the offering', + externalLink: '' + }, + helpComputeOfferingDescription: { + desc: 'A short description of the offering that can be displayed to users', + externalLink: '' + }, + helpComputeOfferingStorageType: { + desc: 'Type of disk for the VM. Local storage is attached to the hypervisor host where the VM is running. Shared storage is accessible via NFS.', + externalLink: '' + }, + helpComputeOfferingProvisioningType: { + desc: 'Provisioning type to create a volume. Thin and sparse is lazy allocation. fat is eager allocation.', + externalLink: '' + }, + helpComputeOfferingCPUCores: { + desc: 'The number of cores which should be allocated to a VM with this offering', + externalLink: '' + }, + helpComputeOfferingCPUMHz: { + desc: 'The CPU speed of the cores that the VM is allocated. For example, 2000 provides a 2 GHz clock.', + externalLink: '' + }, + helpComputeOfferingMemory: { + desc: 'The amount of memory in megabytes to allocate for the system VM. For example, 2048 provides 2 GB RAM.', + externalLink: '' + }, + helpComputeOfferingNetworkRate: { + desc: 'Allowed data transfer rate in megabits(Mb) per second', + externalLink: '' + }, + helpComputeOfferingDiskBytesReadRate: { + desc: 'Allowed disk read rate in bytes per second', + externalLink: '' + }, + helpComputeOfferingDiskBytesWriteRate: { + desc: 'Allowed disk write rate in bytes per second', + externalLink: '' + }, + helpComputeOfferingDiskIopsReadRate: { + desc: 'Allowed disk read rate in I/O requests per second', + externalLink: '' + }, + helpComputeOfferingDiskIopsWriteRate: { + desc: 'Allowed disk write rate in I/O requests per second', + externalLink: '' + }, + helpComputeOfferingHA: { + desc: 'If yes, the administrator can choose to have the VM be monitored and as highly available as possible', + externalLink: '' + }, + helpComputeOfferingStorageTags: { + desc: 'Comma-separated list of attributes that should be associated with the primary storage used by the VM. For example "ssd,blue".', + externalLink: '' + }, + helpComputeOfferingHostTags: { + desc: 'Any tags that you use to organize your hosts', + externalLink: '' + }, + helpComputeOfferingCPUCap: { + desc: 'If yes, the system will limit the level of CPU usage even if spare capacity is available', + externalLink: '' + }, + helpComputeOfferingPublic: { + desc: 'Yes makes the offering available to all domains. No limits the scope to a subdomain; you will be prompted for the subdomain\'s name.', + externalLink: '' + }, + helpComputeOfferingDomain: { + desc: 'Select the domains in which this offering is available (Tip: Use Ctrl to choose multiple domains)', + }, + helpComputeOfferingZone: { + desc: 'Select the zones in which this offering is available (Tip: Use Ctrl to choose multiple zones)', + externalLink: '' + }, + // Create Instance Snapshot + helpCreateInstanceSnapshotName: { + desc: 'Give the snapshot a name. A unique name will be automatically generated if you leave this blank' + }, + helpCreateInstanceSnapshotDescription: { + desc: 'A short description of for the snapshot' + }, + helpCreateInstanceSnapshotMemory: { + desc: 'Check this to include CPU/memory state. Does not quiesce the VM. If not checked, the snapshot contain only volumes.' + }, + // Create instance storage snapshot + helpCreateInstanceStorageSnapshotVolume: { + desc: 'Choose a volume that you want to take a snapshot of' + }, + helpCreateInstanceStorageSnapshotName: { + desc: 'Give the snapshot a name. A unique name will be automatically generated if you leave this blank' + }, + // Add disk offering + helpDiskOfferingName: { + desc: 'Any desired name for the offering', + externalLink: '' + }, + helpDiskOfferingDescription: { + desc: 'A short description of the offering that can be displayed to users', + externalLink: '' + }, + helpDiskOfferingProvisioningType: { + desc: 'Provisioning type to create a volume. Thin and sparse is lazy allocation. fat is eager allocation.', + externalLink: '' + }, + helpDiskOfferingStorageType: { + desc: 'Type of disk for the VM. Local is attached to the hypervisor host where the VM is running. Shared is storage accessible via NFS.', + externalLink: '' + }, + helpDiskOfferingQoSType: { + desc: 'Type of Quality of Service desired, if any.', + externalLink: '' + }, + helpDiskOfferingCustomDiskSize: { + desc: 'If checked, the user can set their own disk size. If not checked, the root administrator must define a value in Disk Size.', + externalLink: '' + }, + helpDiskOfferingDiskSize: { + desc: 'Appears only if Custom Disk Size is not selected. Define the volume size in GB. (1GB = 1,073,741,824 bytes)', + externalLink: '' + }, + helpDiskOfferingDiskBytesReadRate: { + desc: 'Allowed disk read rate in bytes per second', + externalLink: '' + }, + helpDiskOfferingDiskBytesWriteRate: { + desc: 'Allowed disk write rate in bytes per second', + externalLink: '' + }, + helpDiskOfferingDiskIopsReadRate: { + desc: 'Allowed disk read rate in I/O requests per second', + externalLink: '' + }, + helpDiskOfferingDiskIopsWriteRate: { + desc: 'Allowed disk write rate in I/O requests per second', + externalLink: '' + }, + helpDiskOfferingCustomDiskIops: { + desc: 'If checked, the user can set Min and Max IOPS. If not checked, the root administrator can define such values.', + externalLink: '' + }, + helpDiskOfferingDiskIopsMin: { + desc: 'Appears only if Custom IOPS is not selected. Define the minimum volume IOPS.', + externalLink: '' + }, + helpDiskOfferingDiskIopsMax: { + desc: 'Appears only if Custom IOPS is not selected. Define the maximum volume IOPS.', + externalLink: '' + }, + helpDiskOfferingHypervisorSnapshotReserve: { + desc: 'Hypervisor snapshot reserve space as a percent of a volume (for managed storage using XenServer or VMware) (Ex. The value 25 means 25%.)).' + }, + helpDiskOfferingCacheMode: { + desc: 'The write caching mode to use for disks created with this disk offering. This can improve write performance.', + externalLink: '' + }, + helpDiskOfferingStorageTags: { + desc: 'Comma-separated list of attributes that should be associated with the primary storage for this disk. For example "ssd,blue".', + externalLink: '' + }, + helpDiskOfferingPublic: { + desc: 'Yes makes the offering available to all domains. No limits the scope to a subdomain; you will be prompted for the subdomain\'s name.', + externalLink: '' + }, + helpDiskOfferingDomain: { + desc: 'Select the domains in which this offering is available (Tip: Use Ctrl to choose multiple domains)', + externalLink: '' + }, + helpDiskOfferingZone: { + desc: 'Select the zones in which this offering is available (Tip: Use Ctrl to choose multiple zones)', + externalLink: '' + }, + // Add domain + helpDomainName: { + desc: 'Any desired name for the new sub-domain. Must be unique within the current domain.', + externalLink: '' + }, + helpDomainNetworkDomain: { + desc: 'If you want to assign a special domain name to this domain\'s guest VM network, specify the DNS suffix', + externalLink: '' + }, + helpDomainId: { + desc: 'A valid domain id. CloudStack will generate one for you if empty.', + externalLink: '' + }, + // Add F5 + helpF5IPAddress: { + desc: 'The IP address of the device', + externalLink: '' + }, + helpF5Username: { + desc: 'A user ID with valid authentication credentials that provide to access the device', + externalLink: '' + }, + helpF5Password: { + desc: 'The password for the user ID provided in Username', + externalLink: '' + }, + helpF5Type: { + desc: 'The type of device that is being added', + externalLink: '' + }, + helpF5PublicInterface: { + desc: 'Interface of device that is configured to be part of the public network', + externalLink: '' + }, + helpF5PrivateInterface: { + desc: 'Interface of device that is configured to be part of the private network', + externalLink: '' + }, + helpF5Retries: { + desc: 'Number of times to attempt a command on the device before considering the operation failed. Default is 2.', + externalLink: '' + }, + helpF5Mode: { + desc: 'Side by side mode is supported for the F5.', + externalLink: '' + }, + helpF5Dedicated: { + desc: 'Check this box to dedicate the device to a single account. The value in the Capacity field will be ignored.', + externalLink: '' + }, + helpF5Capacity: { + desc: 'Number of guest networks/accounts that will share this device', + externalLink: '' + }, + // Add guest network + helpGuestNetworkName: { + desc: 'The name of the network. This will be user-visible.', + externalLink: '' + }, + helpGuestNetworkDisplayText: { + desc: 'The description of the network. This will be user-visible.', + externalLink: '' + }, + helpGuestNetworkZone: { + desc: 'The name of the zone this network applies to. The administrator must configure the IP range for the guest networks in each zone.', + externalLink: '' + }, + helpGuestNetworkNetworkOffering: { + desc: 'If the administrator has configured multiple network offerings, select the one you want to use for this network', + externalLink: '' + }, + helpGuestNetworkGateway: { + desc: 'The gateway that the guests should use.', + externalLink: '' + }, + helpGuestNetworkNetmask: { + desc: 'The netmask in use on the subnet the guests will use.', + externalLink: '' + }, + // Add guest network from zone + helpGuestNetworkZoneName: { + desc: 'The name of the network. This will be user-visible.', + externalLink: '' + }, + helpGuestNetworkZoneDescription: { + desc: 'The description of the network. This will be user-visible.', + externalLink: '' + }, + helpGuestNetworkZoneVLANID: { + desc: 'The VLAN tag for this network', + externalLink: '' + }, + helpGuestNetworkZoneScope: { + desc: 'Scope', + externalLink: '' + }, + helpGuestNetworkZoneNetworkOffering: { + desc: 'If the administrator has configured multiple network offerings, select the one you want to use for this network', + externalLink: '' + }, + helpGuestNetworkZoneGateway: { + desc: 'The gateway that the guests should use.', + externalLink: '' + }, + helpGuestNetworkZoneNetmask: { + desc: 'The netmask in use on the subnet the guests will use.', + externalLink: '' + }, + helpGuestNetworkZoneStartIP: { + desc: 'The first IP address to define a range that can be assigned to guests. We strongly recommend the use of multiple NICs.', + externalLink: '' + }, + helpGuestNetworkZoneEndIP: { + desc: 'The final IP address to define a range that can be assigned to guests. We strongly recommend the use of multiple NICs.', + externalLink: '' + }, + helpGuestNetworkZoneNetworkDomain: { + desc: 'If you want to assign a special domain name to this guest VM network, specify the DNS suffix', + externalLink: '' + }, + helpGuestNetworkHideIpAddressUsage: { + desc: 'If you want the IP address usage records hidden for the network', + externalLink: '' + }, + // Add host + helpHostZone: { + desc: 'The zone where you want to add the host', + externalLink: '' + }, + helpHostPod: { + desc: 'The pod where you want to add the host', + externalLink: '' + }, + helpHostCluster: { + desc: 'The cluster where you want to add the host', + externalLink: '' + }, + helpHostName: { + desc: 'The DNS name or IP address of the host', + externalLink: '' + }, + helpHostUsername: { + desc: 'Usually root', + externalLink: '' + }, + helpHostPassword: { + desc: 'The password for the user named in Username. The password was set during hypervisor installation on the host.', + externalLink: '' + }, + helpHostTags: { + desc: 'Any labels that you use to categorize hosts for ease of maintenance or to enable HA.', + externalLink: '' + }, + // Add Netscaler + helpNetScalerIPAddress: { + desc: 'The IP address of the device', + externalLink: '' + }, + helpNetScalerUsername: { + desc: 'A user ID with valid authentication credentials that provide to access the device', + externalLink: '' + }, + helpNetScalerPassword: { + desc: 'The password for the user ID provided in Username', + externalLink: '' + }, + helpNetScalerType: { + desc: 'The type of device that is being added', + externalLink: '' + }, + helpNetScalerPublicInterface: { + desc: 'Interface of device that is configured to be part of the public network', + externalLink: '' + }, + helpNetScalerPrivateInterface: { + desc: 'Interface of device that is configured to be part of the private network', + externalLink: '' + }, + helpNetScalerRetries: { + desc: 'Number of times to attempt a command on the device before considering the operation failed. Default is 2.', + externalLink: '' + }, + helpNetScalerDedicated: { + desc: 'Check this box to dedicate the device to a single account. The value in the Capacity field will be ignored.', + externalLink: '' + }, + helpNetScalerCapacity: { + desc: 'Number of guest networks/accounts that will share this device', + externalLink: '' + }, + helpNetscalerServicePackages: { + desc: 'Choose the Netscaler Service Package you want to use.', + externalLink: '' + }, + // Add network offering + helpNetworkOfferingName: { + desc: 'Any desired name for the network offering', + externalLink: '' + }, + helpNetworkOfferingDescription: { + desc: 'A short description of the offering that can be displayed to users', + externalLink: '' + }, + helpNetworkOfferingNetworkRate: { + desc: 'Allowed data transfer rate in megabits(Mb) per second', + externalLink: '' + }, + helpNetworkOfferingTrafficType: { + desc: 'The type of network traffic that will be carried on the network', + externalLink: '' + }, + helpNetworkOfferingGuestType: { + desc: 'Choose whether the guest network is isolated or shared.', + externalLink: '' + }, + helpNetworkOfferingSpecifyVLAN: { + desc: '(Isolated guest networks only) Indicate whether a VLAN should be specified when this offering is used', + externalLink: '' + }, + helpNetworkOfferingVPC: { + desc: 'Specify whether this offering is for a virtual private cloud', + externalLink: '' + }, + helpNetworkOfferingTungsten: { + desc: 'Specify whether this offering is for tungsten SDN', + externalLink: '' + }, + helpNetworkOfferingSystemOffering: { + desc: 'Choose the system service offering that you want the virtual routers to use in this network', + externalLink: '' + }, + helpNetworkOfferingLBIsolation: { + desc: 'Specify what type of load balancer isolation you want for the network: Shared or Dedicated', + externalLink: '' + }, + helpNetworkOfferingMode: { + desc: 'Choose Inline or Side by Side to specify whether a firewall is placed in front of the load balancing device (inline) or in parallel with it (side-by-side)', + externalLink: '' + }, + helpNetworkOfferingAssociatePublicIP: { + desc: 'Select this option if you want to assign a public IP address to the VMs deployed in the guest network', + externalLink: '' + }, + helpNetworkOfferingRedundantRouterCapability: { + desc: 'Select this option if you want to use two virtual routers in the network for uninterrupted connection: one operating as the master virtual router and the other as the backup', + externalLink: '' + }, + helpNetworkOfferingConserveMode: { + desc: 'Check this box to use conserve mode, where network resources are allocated only when the first VM starts. You can define more than one service on the same public IP only when conserve mode is on.', + externalLink: '' + }, + helpNetworkOfferingTags: { + desc: 'Network tag to specify which physical network to use', + externalLink: '' + }, + helpNetworkOfferingPublic: { + desc: 'Yes makes the offering available to all domains. No limits the scope to a subdomain; you will be prompted for the subdomain\'s name.', + externalLink: '' + }, + helpNetworkOfferingDomain: { + desc: 'Select the domains in which this offering is available (Tip: Use Ctrl to choose multiple domains)', + }, + helpNetworkOfferingZone: { + desc: 'Select the zones in which this offering is available (Tip: Use Ctrl to choose multiple zones)', + externalLink: '' + }, + // Add pod + helpPodZone: { + desc: 'The zone where you want to add the pod', + externalLink: '' + }, + helpPodName: { + desc: 'Set a name for the pod', + externalLink: '' + }, + helpPodGateway: { + desc: 'The gateway for the hosts in the pod', + externalLink: '' + }, + helpPodNetmask: { + desc: 'The network prefix that defines the pod\'s subnet.', + externalLink: '' + }, + helpPodStartIP: { + desc: 'The first IP address to define a range in the management network that is used to manage various system VMs', + externalLink: '' + }, + helpPodEndIP: { + desc: 'The last IP address to define a range in the management network that is used to manage various system VMs', + externalLink: '' + }, + // Add primary storage + helpPrimaryStorageZone: { + desc: 'The zone in which you want to create the primary storage', + externalLink: '' + }, + helpPrimaryStoragePod: { + desc: 'The pod in which you want to create the primary storage', + externalLink: '' + }, + helpPrimaryStorageCluster: { + desc: 'The cluster in which you want to create the primary storage', + externalLink: '' + }, + helpPrimaryStorageName: { + desc: 'The name of the storage device', + externalLink: '' + }, + helpPrimaryStorageProtocol: { + desc: 'For XenServer, choose NFS, iSCSI, or PreSetup. For KVM, choose NFS, SharedMountPoint, RDB, CLVM or Gluster. For vSphere, choose VMFS (iSCSI or FiberChannel) or NFS. For Hyper-V, choose SMB/CIFS. For LXC, choose NFS or SharedMountPoint. For OVM, choose NFS or ocfs2.', + externalLink: '' + }, + helpPrimaryStorageServer: { + desc: 'NFS, iSCSI, or PreSetup: IP address or DNS name of the storage device. VMFS: IP address or DNS name of the vCenter server.', + externalLink: '' + }, + helpPrimaryStoragePath: { + desc: 'NFS: exported path from the server. VMFS: /datacenter name/datastore name. SharedMountPoint: path where primary storage is mounted, such as "/mnt/primary"', + externalLink: '' + }, + helpPrimaryStorageSRNameLabel: { + desc: 'The name-label of the SR that has been set up independently of the cloud management system', + externalLink: '' + }, + helpPrimaryStorageTargetIQN: { + desc: 'In iSCSI, this is the IQN of the target. For example, iqn.1986-03.com.sun:02:01ec9bb549-1271378984', + externalLink: '' + }, + helpPrimaryStorageLun: { + desc: 'In iSCSI, this is the LUN number. For example, 3.', + externalLink: '' + }, + helpPrimaryStorageRBDMonitor: { + desc: 'The address of a Ceph monitor. Can also be a Round Robin DNS record', + externalLink: '' + }, + helpPrimaryStorageRBDPool: { + desc: 'The pool to use on the Ceph cluster. This pool should already exist', + externalLink: '' + }, + helpPrimaryStorageRBDId: { + desc: 'The cephx user to use without the client. prefix. For example: admin', + externalLink: '' + }, + helpPrimaryStorageRBDSecret: { + desc: 'The base64 encoded secret of the cephx user.', + externalLink: '' + }, + helpPrimaryStorageTags: { + desc: 'Comma-separated list of tags for this storage device. Must be the same set or a superset of the tags on your disk offerings.', + externalLink: '' + }, + // Add secondary storage + helpSecondaryStorageZone: { + desc: 'The zone in which you want to create the secondary storage', + externalLink: '' + }, + helpSecondaryStorageNFSServer: { + desc: 'The IP address of the server', + externalLink: '' + }, + helpSecondaryStoragePath: { + desc: 'The exported path from the server', + externalLink: '' + }, + // S3 + helpS3AccessKey: { + desc: 'This identifies the S3 user account', + externalLink: '' + }, + helpS3SecretKey: { + desc: 'The password matching the S3 Access Key', + externalLink: '' + }, + helpS3Bucket: { + desc: 'The S3 bucket to store CloudStack data in. The bucket must be created and owned by the same user identified by the S3 Access Key', + externalLink: '' + }, + helpS3Endpoint: { + desc: 'The S3 server to use. Non-standard ports can be appended to the hostname as per s3.amazonaws.com:8080', + externalLink: '' + }, + helpS3ConnectionTimeout: { + desc: 'The number of milliseconds to wait when establishing an S3 connection. This is optional', + externalLink: '' + }, + helpS3MaxErrorRetry: { + desc: 'The number of times to retry S3 requests before failing. This is optional', + externalLink: '' + }, + helpS3SocketTimeout: { + desc: 'The number of milliseconds to wait while reading an S3 response. This is optional', + externalLink: '' + }, + helpNFSStagingServer: { + desc: 'The name or IP address of the NFS secondary staging server', + externalLink: '' + }, + helpNFSStagingPath: { + desc: 'The exported path to use on the NFS staging server', + externalLink: '' + }, + // Add SRX + helpSRXIPAddress: { + desc: 'The IP address of the device', + externalLink: '' + }, + helpSRXUsername: { + desc: 'A user ID with valid authentication credentials that provide to access the device', + externalLink: '' + }, + helpSRXPassword: { + desc: 'The password for the user ID provided in Username', + externalLink: '' + }, + helpSRXType: { + desc: 'The type of device that is being added', + externalLink: '' + }, + helpSRXPublicInterface: { + desc: 'Interface of device that is configured to be part of the public network. For example, ge-0/0/2', + externalLink: '' + }, + helpSRXPrivateInterface: { + desc: 'Interface of device that is configured to be part of the private network. For example, ge-0/0/1', + externalLink: '' + }, + helpSRXUsageInterface: { + desc: 'Interface used to meter traffic. If you don\'t want to use the public interface, specify a different interface name here.', + externalLink: '' + }, + helpSRXRetries: { + desc: 'Number of times to attempt a command on the device before considering the operation failed. Default is 2.', + externalLink: '' + }, + helpSRXTimeout: { + desc: 'The time to wait for a command on the SRX before considering it failed. Default is 300 seconds.', + externalLink: '' + }, + helpSRXMode: { + desc: 'Side by side mode is supported for the SRX.', + externalLink: '' + }, + helpSRXPublicNetwork: { + desc: 'The name of the public network on the SRX. For example, trust.', + externalLink: '' + }, + helpSRXPrivateNetwork: { + desc: 'The name of the private network on the SRX. For example, untrust.', + externalLink: '' + }, + helpSRXDedicated: { + desc: 'Check this box to dedicate the device to a single account. The value in the Capacity field will be ignored.', + externalLink: '' + }, + helpSRXCapacity: { + desc: 'Number of guest networks/accounts that will share this device', + externalLink: '' + }, + // Add Palo Alto + helpPaloAltoIPAddress: { + desc: 'The IP address of the device', + externalLink: '' + }, + helpPaloAltoUsername: { + desc: 'A user ID with valid authentication credentials that provide to access the device', + externalLink: '' + }, + helpPaloAltoPassword: { + desc: 'The password for the user ID provided in Username', + externalLink: '' + }, + helpPaloAltoType: { + desc: 'The type of device that is being added', + externalLink: '' + }, + helpPaloAltoPublicInterface: { + desc: 'Interface of device that is configured to be part of the public network. For example, ge-0/0/2', + externalLink: '' + }, + helpPaloAltoPrivateInterface: { + desc: 'Interface of device that is configured to be part of the private network. For example, ge-0/0/1', + externalLink: '' + }, + helpPaloAltoUsageInterface: { + desc: 'Interface used to meter traffic. If you don\'t want to use the public interface, specify a different interface name here.', + externalLink: '' + }, + helpPaloAltoRetries: { + desc: 'Number of times to attempt a command on the device before considering the operation failed. Default is 2.', + externalLink: '' + }, + helpPaloAltoTimeout: { + desc: 'The time to wait for a command on the Palo Alto before considering it failed. Default is 300 seconds.', + externalLink: '' + }, + helpPaloAltoMode: { + desc: 'Side by side mode is supported for the Palo Alto.', + externalLink: '' + }, + helpPaloAltoPublicNetwork: { + desc: 'The name of the public network on the Palo Alto. For example, trust.', + externalLink: '' + }, + helpPaloAltoPrivateNetwork: { + desc: 'The name of the private network on the Palo Alto. For example, untrust.', + externalLink: '' + }, + helpPaloAltoVirtualRouter: { + desc: 'The name of the virtual router on the Palo Alto.', + externalLink: '' + }, + helpPaloAltoThreatProfile: { + desc: 'The threat profile name/group to associate with allow firewall policies.', + externalLink: '' + }, + helpPaloAltoLogProfile: { + desc: 'The log profile name/group to associate with allow firewall policies.', + externalLink: '' + }, + helpPaloAltoDedicated: { + desc: 'Check this box to dedicate the device to a single account. The value in the Capacity field will be ignored.', + externalLink: '' + }, + helpPaloAltoCapacity: { + desc: 'Number of guest networks/accounts that will share this device', + externalLink: '' + }, + // Add system service offering + helpSystemOfferingName: { + desc: 'Any desired name for the offering', + externalLink: '' + }, + helpSystemOfferingDescription: { + desc: 'A short description of the offering that can be displayed to the root administrator', + externalLink: '' + }, + helpSystemOfferingVMType: { + desc: 'The type of system VM that is being offered', + externalLink: '' + }, + helpSystemOfferingStorageType: { + desc: 'Type of disk for the system VM. Local storage is attached to the host where the system VM is running. Shared storage is accessible via NFS.', + externalLink: '' + }, + helpSystemOfferingCPUCores: { + desc: 'The number of cores which should be allocated to a system VM with this offering', + externalLink: '' + }, + helpSystemOfferingCPUMHz: { + desc: 'The CPU speed of the cores that the system VM is allocated. For example, 2000 would provide for a 2 GHz clock.', + externalLink: '' + }, + helpSystemOfferingMemory: { + desc: 'The amount of memory in megabytes to allocate for the system VM. For example, 2048 provides 2 GB RAM.', + externalLink: '' + }, + helpSystemOfferingNetworkRate: { + desc: 'Allowed data transfer rate in megabits(Mb) per second', + externalLink: '' + }, + helpSystemOfferingDiskBytesReadRate: { + desc: 'Allowed disk read rate in bytes per second', + externalLink: '' + }, + helpSystemOfferingDiskBytesWriteRate: { + desc: 'Allowed disk write rate in bytes per second', + externalLink: '' + }, + helpSystemOfferingDiskIopsReadRate: { + desc: 'Allowed disk read rate in I/O requests per second', + externalLink: '' + }, + helpSystemOfferingDiskIopsWriteRate: { + desc: 'Allowed disk write rate in I/O requests per second', + externalLink: '' + }, + helpSystemOfferingHA: { + desc: 'If yes, the administrator can choose to have the system VM be monitored and as highly available as possible', + externalLink: '' + }, + helpSystemOfferingStorageTags: { + desc: 'Comma-separated list of attributes that should be associated with the primary storage used by the system VM. For example "ssd,blue".', + externalLink: '' + }, + helpSystemOfferingHostTags: { + desc: 'Any tags that you use to organize your hosts', + externalLink: '' + }, + helpSystemOfferingCPUCap: { + desc: 'If yes, the system will limit the level of CPU usage even if spare capacity is available', + externalLink: '' + }, + helpSystemOfferingPublic: { + desc: 'Yes makes the offering available to all domains. No limits the scope to a subdomain; you will be prompted for the subdomain\'s name.', + externalLink: '' + }, + helpSystemOfferingDomain: { + desc: 'Select the subdomain in which this offering is available', + externalLink: '' + }, + // Add tier + helpTierName: { + desc: 'A unique name for the tier', + externalLink: '' + }, + helpTierNetworkOffering: { + desc: 'If the administrator has configured multiple network offerings, select the one you want to use for this tier', + externalLink: '' + }, + helpTierGateway: { + desc: 'The gateway for the tier. Must be in the Super CIDR range of the VPC and not overlapping the CIDR of any other tier in this VPC.', + externalLink: '' + }, + helpTierNetmask: { + desc: 'Netmask for the tier. For example, with VPC CIDR of 10.0.0.0/16 and network tier CIDR of 10.0.1.0/24, gateway is 10.0.1.1 and netmask is 255.255.255.0', + externalLink: '' + }, + // Add user + helpUserUsername: { + desc: 'Any desired user ID. Must be unique in the current domain. The same username can exist in other domains, including sub-domains.', + externalLink: '' + }, + helpUserPassword: { + desc: 'Any desired user password', + externalLink: '' + }, + helpUserConfirmPassword: { + desc: 'Type the same password again', + externalLink: '' + }, + helpUserEmail: { + desc: 'The user\'s email address', + externalLink: '' + }, + helpUserFirstName: { + desc: 'The user\'s first name, also known as the given name', + externalLink: '' + }, + helpUserLastName: { + desc: 'The user\'s last name, also known as the family name', + externalLink: '' + }, + helpUserTimezone: { + desc: 'Set the time zone that corresponds to the user\'s locale', + externalLink: '' + }, + // Add volume + helpVolumeName: { + desc: 'Give a unique volume name. If it is not provided, a name will be generated randomly.', + externalLink: '' + }, + helpVolumeAvailabilityZone: { + desc: 'Where do you want the storage to reside? This should be close to the VM that will use the volume.', + externalLink: '' + }, + helpVolumeDiskOffering: { + desc: 'Choose the characteristics of the storage.', + externalLink: '' + }, + helpVolumeSizeGb: { + desc: 'Volume size in GB (1GB = 1,073,741,824 bytes)', + externalLink: '' + }, + // Add VPC + helpVPCName: { + desc: 'A name for the new VPC', + externalLink: '' + }, + helpVPCDescription: { + desc: 'Display text about the VPC', + externalLink: '' + }, + helpVPCZone: { + desc: 'Zone where you want the VPC to be available', + externalLink: '' + }, + helpVPCSuperCIDR: { + desc: 'CIDR range for all the tiers within a VPC. Each tier\'s CIDR must be within the Super CIDR.', + externalLink: '' + }, + helpVPCDomain: { + desc: 'If you want to assign a special domain name to this VPC\'s guest VM network, specify the DNS suffix', + externalLink: '' + }, + // Add VPC gateway + helpVPCGatewayPhysicalNetwork: { + desc: 'Name of a physical network that has been created in the zone', + externalLink: '' + }, + helpVPCGatewayVLAN: { + desc: 'The VLAN associated with the VPC gateway', + externalLink: '' + }, + helpVPCGatewayIP: { + desc: 'The IP address associated with the VPC gateway', + externalLink: '' + }, + helpVPCGatewayGateway: { + desc: 'The gateway through which the traffic is routed to and from the VPC', + externalLink: '' + }, + helpVPCGatewayNetmask: { + desc: 'The netmask associated with the VPC gateway', + externalLink: '' + }, + // Add VPN customer gateway + helpVPNGatewayName: { + desc: 'A unique name for the VPN customer gateway', + externalLink: '' + }, + helpVPNGatewayGateway: { + desc: 'The IP address for the remote gateway', + externalLink: '' + }, + helpVPNGatewayCIDRList: { + desc: 'The guest CIDR list of the remote subnets. Enter a CIDR or a comma-separated list. Do not overlap the VPC\'s CIDR or another guest CIDR.', + externalLink: '' + }, + helpVPNGatewayIPsecPresharedKey: { + desc: 'Enter a secret key value. The endpoints of the VPN share a secret key. This is used to authenticate the customer gateway and the VPC VPN gateway to each other.', + externalLink: '' + }, + helpVPNGatewayIKEEncryption: { + desc: 'Enter AES128, AES192, AES256, or 3DES to specify the Internet Key Exchange (IKE) policy for phase-1. Authentication is accomplished with Preshared Keys.', + externalLink: '' + }, + helpVPNGatewayIKEHash: { + desc: 'Enter SHA1 or MD5 to specify the IKE hash algorithm for phase-1', + externalLink: '' + }, + helpVPNGatewayIKEDH: { + desc: 'Enter Group-5 (1536-bit), Group-2 (1024-bit), or None to specify the public-key cryptography protocol to use. The 1536-bit Diffie-Hellman group is used within IKE to establish session keys.', + externalLink: '' + }, + helpVPNGatewayESPEncryption: { + desc: 'Enter AES128, AES192, AES256, or 3DES to specify the Encapsulating Security Payload (ESP) algorithm within phase-2', + externalLink: '' + }, + helpVPNGatewayESPHash: { + desc: 'Enter SHA1 or MD5 to specify the Encapsulating Security Payload (ESP) hash for phase-2', + externalLink: '' + }, + helpVPNGatewayPerfectForwardSecrecy: { + desc: 'Choose Group-5 (1536-bit), Group-2 (1024-bit), or None to specify whether to enforce a new Diffie-Hellman key exchange and, if so, what size of DH group to use', + externalLink: '' + }, + helpVPNGatewayIKELifetime: { + desc: 'The phase-1 lifetime of the security association in seconds. Whenever the time expires, a new phase-1 exchange is performed.', + externalLink: '' + }, + helpVPNGatewayESPLifetime: { + desc: 'The phase-2 lifetime of the security association in seconds. Whenever the time expires, a re-key is initiated to provide a new IPsec encryption and authentication session keys.', + externalLink: '' + }, + helpVPNGatewayDeadPeerDetection: { + desc: 'Check this to make the virtual router query its IKE peer at regular intervals to ensure continued availability. It is recommended to have the same DPD setting on both sides of the VPN connection.', + externalLink: '' + }, + helpVPNGatewayForceEncapsulation: { + desc: 'Force UDP encapsulation for ESP packets even if no NAT situation is detected. This may help to surmount restrictive firewalls. In order to force the peer to encapsulate packets, NAT detection payloads are faked', + externalLink: '' + }, + // Copy template + helpCopyTemplateDestination: { + desc: 'The zone to which you want to copy the template', + externalLink: '' + }, + // Enter token + helpEnterTokenProjectID: { + desc: 'Unique identifying number for the project. Use the number you received in the invitation email', + externalLink: '' + }, + helpEnterTokenToken: { + desc: 'Unique security code that authorizes you to accept the project invitation. Use the token you received in the invitation email', + externalLink: '' + }, + // Register template + helpRegisterTemplate: { + desc: '', + externalLink: '' + }, + // Register template + helpRegisterTemplate: { + desc: '', + externalLink: '' + }, + // Register ISO + helpRegisterISOName: { + desc: 'A unique name for the ISO. This will be visible to users, so choose something descriptive.', + externalLink: '' + }, + helpRegisterISODescription: { + desc: 'Display text describing the ISO. This will be visible to users, so choose something descriptive.', + externalLink: '' + }, + helpRegisterISOURL: { + desc: 'The Management Server will download the file from the specified URL, such as http://my.web.server/filename.iso', + externalLink: '' + }, + helpRegisterISODirectDownload: { + desc: 'KVM Only: Secondary Storage is bypassed and ISO is downloaded to Primary Storage on deployment', + externalLink: '' + }, + helpRegisterISOZone: { + desc: 'Choose the zone where you want the ISO to be available, or All Zones to make it available throughout the cloud', + externalLink: '' + }, + helpRegisterISOBootable: { + desc: 'Indicate whether the machine can be booted using this ISO', + externalLink: '' + }, + helpRegisterISOOSType: { + desc: 'Operating system of the VM represented by the ISO. If the OS type of the ISO is not listed, choose Other.', + externalLink: '' + }, + helpRegisterISOExtractable: { + desc: 'Whether the ISO is downloadable by users or not', + externalLink: '' + }, + helpRegisterISOPublic: { + desc: 'Check this to make the ISO accessible to all users. The ISO will appear in the Community ISOs list.', + externalLink: '' + }, + helpRegisterISOFeatured: { + desc: 'Check this to make the ISO more prominent for users. The ISO will appear in the Featured ISOs list.', + externalLink: '' + }, + // Register template + helpRegisterTemplateName: { + desc: 'A unique name for the template. This will be visible to users, so choose something descriptive.', + externalLink: '' + }, + helpRegisterTemplateDescription: { + desc: 'Display text describing the template. This will be visible to users, so choose something descriptive.', + externalLink: '' + }, + helpRegisterTemplateURL: { + desc: 'The Management Server will download the file from the specified URL, such as http://my.web.server/filename.vhd.gz', + externalLink: '' + }, + helpRegisterTemplateDirectDownload: { + desc: 'KVM Only: Secondary Storage is bypassed and template/ISO is downloaded to Primary Storage on deployment', + externalLink: '' + }, + helpRegisterTemplateZone: { + desc: 'Choose one or more zones where you want the template to be available, or All Zones to make it available throughout the cloud. (Tip: Use Ctrl to choose multiple zones)', + externalLink: '' + }, + helpRegisterTemplateHypervisor: { + desc: 'The hypervisor software from which this template is being imported; this determines the value of Format', + externalLink: '' + }, + helpRegisterTemplateFormat: { + desc: 'The data format of the template upload file', + externalLink: '' + }, + helpRegisterTemplateOSType: { + desc: 'Operating system of the VM represented by the template. If the OS type of the template is not listed, choose Other.', + externalLink: '' + }, + helpRegisterTemplateExtractable: { + desc: 'Whether the template is downloadable by users or not', + externalLink: '' + }, + helpRegisterTemplateDynamicallyScalable: { + desc: 'Check this if the template contains XS/VMWare tools to support dynamic scaling of VM cpu/memory.', + externalLink: '' + }, + helpRegisterTemplatePasswordEnabled: { + desc: 'Check this if the template has the password change script installed.', + externalLink: '' + }, + helpRegisterTemplatePublic: { + desc: 'Check this to make the template accessible to all users. The template will appear in the Community Templates list.', + externalLink: '' + }, + helpRegisterTemplateFeatured: { + desc: 'Check this to make the template more prominent for users. The template will appear in the Featured Templates list.', + externalLink: '' + }, + helpRegisterTemplateRouting: { + desc: 'Check this if the template is used for deploying router.', + externalLink: '' + }, + helpRegisterTemplateHvm: { + desc: 'Check this if the template requires hvm.', + externalLink: '' + }, + // Upload volume + helpUploadVolumeName: { + desc: 'A unique name for the volume. This will be visible to users, so choose something descriptive.', + externalLink: '' + }, + helpUploadVolumeZone: { + desc: 'Choose the zone where you want to store the volume. VMs running on hosts in this zone can attach the volume.', + externalLink: '' + }, + helpUploadVolumeFormat: { + desc: 'The disk image format of the volume. XenServer is VHD, VMware is OVA, and KVM is QCOW2. Hyper-V is VHD or VHDX. OVM is RAW.', + externalLink: '' + }, + helpUploadVolumeURL: { + desc: 'Secure HTTP or HTTPS URL that can be used to get the disk. File type must match Format. For example, if Format is VHD, http://yourFileServerIP/userdata/myDataDisk.vhd', + externalLink: '' + }, + helpUploadVolumeChecksum: { + desc: 'Use the hash that you created at the start of the volume upload procedure', + externalLink: '' + }, + helpLdapGroupName: { + desc: 'The group name from which you want to import LDAP users', + externalLink: '' + }, + helpSamlEnable: { + desc: 'Enable SAML Single Sign On for the user(s)', + externalLink: '' + }, + helpSamlEntity: { + desc: 'Choose the SAML Identity Provider Entity ID with which you want to enable the Single Sign On for the user(s)', + externalLink: '' + }, + helpVpcOfferingName: { + desc: 'Any desired name for the VPC offering', + externalLink: '' + }, + helpVpcOfferingDescription: { + desc: 'A short description of the offering that can be displayed to users', + externalLink: '' + }, + helpVpcOfferingPublic: { + desc: 'Yes makes the offering available to all domains. No limits the scope to a subdomain; you will be prompted for the subdomain\'s name.', + externalLink: '' + }, + helpVpcOfferingDomain: { + desc: 'Select the domains in which this offering is available (Tip: Use Ctrl to choose multiple domains)', + }, + helpVpcOfferingZone: { + desc: 'Select the zones in which this offering is available (Tip: Use Ctrl to choose multiple zones)', + externalLink: '' + }, + helpOvm3pool: { + desc: 'Pool the Ovm3 nodes in this cluster, required for vm node migrations', + externalLink: '' + }, + helpOvm3cluster: { + desc: 'Use the native Ovm3 OCFS2 clustering, required for native HA and requires pooling', + externalLink: '' + }, + helpOvm3Vip: { + desc: 'The VIP used by the pool and cluster', + externalLink: '' + }, + helpLdapGroupName: { + desc: 'Fully qualified name of OU/GROUP in LDAP', + externalLink: '' + }, + helpLdapGroupType: { + desc: 'Type of LDAP name provided. Can be either GROUP/OU', + externalLink: '' + }, + helpLdapLinkDomainAdmin: { + desc: 'domain admin of the linked domain. Specify a username in GROUP/OU of LDAP' + }, + helpSetReservationSystemVms: { + desc: 'If enabled, IP range reservation is set for SSVM & CPVM. Global setting "system.vm.public.ip.reservation.mode.strictness" is used to control whether reservation is strict or not (preferred)' + }, + helpL2UserData: { + desc: 'Pass user and meta data to VMs (via ConfigDrive)', + externalLink: '' + }, + helpComputeOfferingMinCPUCores: { + desc: 'This will be used for the setting the range (min-max) of the number of cpu cores that should be allowed for VMs using this custom offering.', + externalLink: '' + }, + helpComputeOfferingMaxCPUCores: { + desc: 'This will be used for the setting the range (min-max) of the number of cpu cores that should be allowed for VMs using this custom offering.', + externalLink: '' + }, + helpComputeOfferingMinMemory: { + desc: 'This will be used for the setting the range (min-max) amount of memory that should be allowed for VMs using this custom offering.', + externalLink: '' + }, + helpComputeOfferingMaxMemory: { + desc: 'This will be used for the setting the range (min-max) amount of memory that should be allowed for VMs using this custom offering.', + externalLink: '' + }, + helpComputeOfferingType: { + desc: 'This will be used for setting the type of compute offering - whether it is fixed, custom constrained or custom unconstrained.', + externalLink: '' + }, + + // Update Template Permissions Helper + helpUpdateTemplateOperation: { + desc: 'Select the permission operator. Add is for sharing with user/project and Reset simply removes all the accounts and projects which template has been shared with.' + }, + helpUpdateTemplateShareWith: { + desc: 'Select account or project with which template is to be shared with.' + }, + helpUpdateTemplateAccounts: { + desc: 'Choose one or more accounts to share this template. Ctrl+Click to select multiple accounts to share with. Selecting "Add > Accounts" shows list of accounts that do not have permissions. Selecting "Remove > Accounts" shows list of accounts that already have permissions.' + }, + helpUpdateTemplateProjectIds: { + desc: 'Choose one or more projects to share this template. Ctrl+Click to select multiple projects to share with. Selecting "Add > Projects" shows list of projects that do not have permissions. Selecting "Remove > Projects" shows list of projects that already have permissions.' + }, + helpUpdateTemplateAccountList: { + desc: 'A comma seperated list of accounts to share the template with. Must be specified with the Add/Remove operation, leave Project ID blank if this is specified.' + } +}; diff --git a/ui/scripts/network.js b/ui/scripts/network.js new file mode 100644 index 000000000000..2cc919537d1f --- /dev/null +++ b/ui/scripts/network.js @@ -0,0 +1,7174 @@ +// 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. + +(function(cloudStack, $) { + var ingressEgressDataMap = function(elem) { + var elemData = { + id: elem.ruleid, + protocol: elem.protocol, + startport: elem.startport, + endport: elem.endport, + cidr: elem.cidr ? elem.cidr : ''.concat(elem.account, ' - ', elem.securitygroupname), + tags: elem.tags + }; + + if (typeof elem.icmptype != 'undefined') { + var icmptype = elem.icmptype.toString() + } + + if (typeof elem.icmpcode != 'undefined') { + var icmpcode = elem.icmpcode.toString() + } + + if (elemData.startport == 0 && elemData.endport) { + elemData.startport = '0'; + } else if (icmptype && icmpcode) { + elemData.startport = icmptype; + elemData.endport = icmpcode; + } + + if (elemData.protocol != 'tcp' && elemData.protocol != 'udp' && elemData.protocol != 'icmp') { + elemData.startport = 'all'; + elemData.endport = 'all'; + } + return elemData; + }; + + //value of Primary IP in subselect dropdown is -1, for single VM selection (API parameter virtualmachineid + vmguestip), e.g. enableStaticNat API, createPortForwardingRule API. + var singleVmSecondaryIPSubselect = function(args) { + var instance = args.context.instances[0]; + var network = args.context.networks[0]; + + if (args.context.ipAddresses[0].isportable) { //portable IP which has multiple NICs. Each NIC has a different network ID. + $.ajax({ + url: createURL('listNics'), + data: { + virtualmachineid: instance.id + }, + success: function(json) { + var nics = json.listnicsresponse.nic; + var ipSelection = []; + + $(nics).map(function(index, nic) { + var primaryIp = nic.ipaddress; + var secondaryIps = nic.secondaryip ? nic.secondaryip : []; + var prefix = '[NIC ' + (index + 1) + '] '; + + // Add primary IP as default + ipSelection.push({ + id: nic.networkid + ',-1', + description: prefix + primaryIp + ' (Primary)' + }); + + // Add secondary IPs + $(secondaryIps).map(function(index, secondaryIp) { + ipSelection.push({ + id: nic.networkid + ',' + secondaryIp.ipaddress, + description: prefix + secondaryIp.ipaddress + }); + }); + }); + + args.response.success({ + data: ipSelection + }); + } + }); + + } else { //non-portable IP which has only one NIC + // Get NIC IPs + $.ajax({ + url: createURL('listNics'), + data: { + virtualmachineid: instance.id, + networkid: (args.context.networkid != undefined) ? args.context.networkid : network.id + }, + success: function(json) { + var nic = json.listnicsresponse.nic[0]; + var primaryIp = nic.ipaddress; + var secondaryIps = nic.secondaryip ? nic.secondaryip : []; + var ipSelection = []; + + // Add primary IP as default + ipSelection.push({ + id: primaryIp, + description: primaryIp + ' (Primary)' + }); + + // Add secondary IPs + $(secondaryIps).map(function(index, secondaryIp) { + ipSelection.push({ + id: secondaryIp.ipaddress, + description: secondaryIp.ipaddress + }); + }); + + args.response.success({ + data: ipSelection + }); + } + }); + } + }; + + //value of Primary IP in subselect dropdown is itself (not -1), for multiple VM selection (API parameter vmidipmap), e.g. assignToLoadBalancerRule API. + var multipleVmSecondaryIPSubselect = function(args) { + var instance = args.context.instances[0]; + var network = args.context.networks[0]; + + if (args.context.ipAddresses[0].isportable) { //portable IP which has multiple NICs. Each NIC has a different network ID. + $.ajax({ + url: createURL('listNics'), + data: { + virtualmachineid: instance.id + }, + success: function(json) { + var nics = json.listnicsresponse.nic; + var ipSelection = []; + + //portable IP has multiple NICs. Each NIC has a different network ID. + $(nics).map(function(index, nic) { + var primaryIp = nic.ipaddress; + var secondaryIps = nic.secondaryip ? nic.secondaryip : []; + var prefix = '[NIC ' + (index + 1) + '] '; + + // Add primary IP as default + ipSelection.push({ + id: nic.networkid + ',' + primaryIp, + description: prefix + primaryIp + ' (Primary)' + }); + + // Add secondary IPs + $(secondaryIps).map(function(index, secondaryIp) { + ipSelection.push({ + id: nic.networkid + ',' + secondaryIp.ipaddress, + description: prefix + secondaryIp.ipaddress + }); + }); + }); + + args.response.success({ + data: ipSelection + }); + } + }); + + } else { //non-portable IP which has only one NIC + // Get NIC IPs + $.ajax({ + url: createURL('listNics'), + data: { + virtualmachineid: instance.id, + networkid: network.id + }, + success: function(json) { + var nic = json.listnicsresponse.nic[0]; + var primaryIp = nic.ipaddress; + var secondaryIps = nic.secondaryip ? nic.secondaryip : []; + var ipSelection = []; + var existingIps = $(args.context.subItemData).map( + function(index, item) { return item.itemIp; } + ); + + // Add primary IP as default + if ($.inArray(primaryIp, existingIps) == -1) { + ipSelection.push({ + id: primaryIp, + description: primaryIp + ' (Primary)' + }); + } + + // Add secondary IPs + $(secondaryIps).map(function(index, secondaryIp) { + if ($.inArray(secondaryIp.ipaddress, existingIps) == -1) { + ipSelection.push({ + id: secondaryIp.ipaddress, + description: secondaryIp.ipaddress + }); + } + }); + + args.response.success({ + data: ipSelection + }); + } + }); + } + }; + + var ipChangeNotice = function() { + cloudStack.dialog.confirm({ + message: 'message.ip.address.changed', + action: function() { + $('#browser .container').cloudBrowser('selectPanel', { + panel: $('#browser .panel:last').prev(), + complete: function() { + $(window).trigger('cloudStack.fullRefresh'); + } + }); + } + }); + }; + + var zoneObjs = []; + + var actionFilters = { + ipAddress: function(args) { + var allowedActions = args.context.actions; + var disallowedActions = []; + var ipObj = args.context.item; + var status = ipObj.state; + + //***** apply to both Isolated Guest Network IP, VPC IP (begin) ***** + if (status == 'Destroyed' || + status == 'Releasing' || + status == 'Released' || + status == 'Creating' || + status == 'Allocating' || + ipObj.account == 'system' || + ipObj.issystem == true) { + return []; + } + + if (ipObj.issourcenat) { //sourceNAT IP doesn't support staticNAT + disallowedActions.push('enableStaticNAT'); + disallowedActions.push('disableStaticNAT'); + disallowedActions.push('remove'); + } else { //non-sourceNAT IP supports staticNAT + disallowedActions.push('enableVPN'); + if (ipObj.isstaticnat) { + disallowedActions.push('enableStaticNAT'); + } else { + disallowedActions.push('disableStaticNAT'); + } + } + //***** apply to both Isolated Guest Network IP, VPC IP (end) ***** + + + if (!('vpc' in args.context)) { //***** Guest Network section > Guest Network page > IP Address page ***** + if (args.context.networks[0].networkofferingconservemode == false) { + /* + (1) If IP is SourceNat, no StaticNat/VPN/PortForwarding/LoadBalancer can be enabled/added. + */ + if (ipObj.issourcenat == true) { + disallowedActions.push('enableStaticNAT'); + disallowedActions.push('enableVPN'); + } + + /* + (2) If IP is non-SourceNat, show StaticNat/VPN/PortForwarding/LoadBalancer at first. + 1. Once StaticNat is enabled, hide VPN/PortForwarding/LoadBalancer. + 2. Once VPN is enabled, hide StaticNat/PortForwarding/LoadBalancer. + 3. Once a PortForwarding rule is added, hide StaticNat/VPN/LoadBalancer. + 4. Once a LoadBalancer rule is added, hide StaticNat/VPN/PortForwarding. + */ + else { //ipObj.issourcenat == false + if (ipObj.isstaticnat) { //1. Once StaticNat is enabled, hide VPN/PortForwarding/LoadBalancer. + disallowedActions.push('enableVPN'); + } + if (ipObj.vpnenabled) { //2. Once VPN is enabled, hide StaticNat/PortForwarding/LoadBalancer. + disallowedActions.push('enableStaticNAT'); + } + + //3. Once a PortForwarding rule is added, hide StaticNat/VPN/LoadBalancer. + $.ajax({ + url: createURL('listPortForwardingRules'), + data: { + ipaddressid: ipObj.id, + listAll: true + }, + dataType: 'json', + async: false, + success: function(json) { + var rules = json.listportforwardingrulesresponse.portforwardingrule; + if (rules != null && rules.length > 0) { + disallowedActions.push('enableVPN'); + disallowedActions.push('enableStaticNAT'); + } + } + }); + + //4. Once a LoadBalancer rule is added, hide StaticNat/VPN/PortForwarding. + $.ajax({ + url: createURL('listLoadBalancerRules'), + data: { + publicipid: ipObj.id, + listAll: true + }, + dataType: 'json', + async: false, + success: function(json) { + var rules = json.listloadbalancerrulesresponse.loadbalancerrule; + if (rules != null && rules.length > 0) { + disallowedActions.push('enableVPN'); + disallowedActions.push('enableStaticNAT'); + } + } + }); + } + } + + if (ipObj.networkOfferingHavingVpnService == true) { + if (ipObj.vpnenabled) { + disallowedActions.push('enableVPN'); + } else { + disallowedActions.push('disableVPN'); + } + } else { //ipObj.networkOfferingHavingVpnService == false + disallowedActions.push('disableVPN'); + disallowedActions.push('enableVPN'); + } + } else { //***** VPC section > Configuration VPC > Router > Public IP Addresses ***** + if (ipObj.issourcenat) { //VPC sourceNAT IP: supports VPN + if (ipObj.vpnenabled) { + disallowedActions.push('enableVPN'); + } else { + disallowedActions.push('disableVPN'); + } + } else { //VPC non-sourceNAT IP: doesn't support VPN + disallowedActions.push('enableVPN'); + disallowedActions.push('disableVPN'); + } + } + + allowedActions = $.grep(allowedActions, function(item) { + return $.inArray(item, disallowedActions) == -1; + }); + + return allowedActions; + }, + + securityGroups: function(args) { + var allowedActions = []; + var isSecurityGroupOwner = isAdmin() || isDomainAdmin() || + args.context.item.account == args.context.users[0].account; + + if (isSecurityGroupOwner && + args.context.item.state != 'Destroyed' && + args.context.item.name != 'default') { + allowedActions.push('remove'); + allowedActions.push('edit'); + } + + return allowedActions; + } + }; + + var networkOfferingObjs = []; + var advZoneObjs; + + cloudStack.sections.network = { + title: 'label.network', + id: 'network', + sectionSelect: { + preFilter: function(args) { + var sectionsToShow = ['networks']; + var securityGroupsEnabledFound = false; //Until we found a zone where securitygroupsenabled is true. + + //This call to show VPC and VPN Customer Gateway sections, if zone is advanced. + $.ajax({ + url: createURL('listZones'), + data: { + networktype: 'Advanced' + }, + async: false, + success: function(json) { + advZoneObjs = json.listzonesresponse ? json.listzonesresponse.zone : null; + if (advZoneObjs != null && advZoneObjs.length > 0) { + sectionsToShow.push('vpc'); + sectionsToShow.push('vpnCustomerGateway'); + + //At the same time check if any advanced zone has securitygroupsenabled is true. + //If so, show Security Group section. + for (var i = 0; (i < advZoneObjs.length) && !securityGroupsEnabledFound; i++) { + if (advZoneObjs[i].securitygroupsenabled) { + securityGroupsEnabledFound = true; + sectionsToShow.push('securityGroups'); + } + } + } + //Ajax call to check if VPN is enabled. + $.ajax({ + url: createURL('listRemoteAccessVpns'), + data: { + listAll: true + }, + async: false, + success: function(vpnResponse) { + var isVPNEnabled = vpnResponse.listremoteaccessvpnsresponse.count; + + if (isVPNEnabled) { + sectionsToShow.push('vpnuser'); + } + } + }); + } + }); + + //If we didn't find any advanced zone whose securitygroupsenabled is true. + //Search in all Basic zones. + if (!securityGroupsEnabledFound) { + $.ajax({ + url: createURL('listZones'), + data: { + networktype: 'Basic' + }, + async: false, + success: function(json) { + var basicZoneObjs = json.listzonesresponse ? json.listzonesresponse.zone : null; + if (basicZoneObjs != null && basicZoneObjs.length > 0) { + sectionsToShow.push('securityGroups'); + } + } + }); + } + + return sectionsToShow; + }, + + label: 'label.select-view' + }, + sections: { + networks: { + id: 'networks', + type: 'select', + title: 'label.guest.networks', + listView: { + actions: { + add: { + label: 'label.add.isolated.network', + + preFilter: function(args) { + if (advZoneObjs != null && advZoneObjs.length > 0) { + for (var i = 0; i < advZoneObjs.length; i++) { + if (advZoneObjs[i].securitygroupsenabled != true) { //'Add Isolated Guest Network with SourceNat' is only supported in Advanced SG-disabled zone + return true; + } + } + return false; + } else { + return false; + } + }, + + createForm: { + title: 'label.add.isolated.guest.network.with.sourcenat', + fields: { + name: { + label: 'label.name', + validation: { + required: true + }, + docID: 'helpGuestNetworkName' + }, + displayText: { + label: 'label.display.text', + validation: { + required: true + }, + docID: 'helpGuestNetworkDisplayText' + }, + zoneId: { + label: 'label.zone', + validation: { + required: true + }, + docID: 'helpGuestNetworkZone', + + select: function(args) { + $.ajax({ + url: createURL('listZones'), + success: function(json) { + var zones = $.grep(json.listzonesresponse.zone, function(zone) { + return (zone.networktype == 'Advanced' && zone.securitygroupsenabled != true); //Isolated networks can only be created in Advanced SG-disabled zone (but not in Basic zone nor Advanced SG-enabled zone) + }); + + args.response.success({ + data: $.map(zones, function(zone) { + return { + id: zone.id, + description: zone.name + }; + }) + }); + } + }); + } + }, + domain: { + label: 'label.domain', + isHidden: function(args) { + if (isAdmin() || isDomainAdmin()) + return false; + else + return true; + }, + select: function(args) { + if (isAdmin() || isDomainAdmin()) { + $.ajax({ + url: createURL("listDomains&listAll=true"), + success: function(json) { + var items = []; + items.push({ + id: "", + description: "" + }); + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + args.$select.change(function() { + var $form = $(this).closest('form'); + if ($(this).val() == "") { + $form.find('.form-item[rel=account]').hide(); + } else { + $form.find('.form-item[rel=account]').css('display', 'inline-block'); + } + }); + } else { + args.response.success({ + data: null + }); + } + } + }, + networkOfferingId: { + label: 'label.network.offering', + validation: { + required: true + }, + dependsOn: (isAdmin() || isDomainAdmin()) ? ['zoneId', 'domain'] : 'zoneId', // domain is visible only for admins + docID: 'helpGuestNetworkNetworkOffering', + select: function(args) { + var data = { + zoneid: args.zoneId, + guestiptype: 'Isolated', + supportedServices: 'SourceNat', + state: 'Enabled' + }; + + if ((isAdmin() || isDomainAdmin())) { // domain is visible only for admins + $.extend(data, { + domainid: args.domain + }); + } + + if ('vpc' in args.context) { //from VPC section + $.extend(data, { + forVpc: true + }); + } + else { //from guest network section + var vpcs; + $.ajax({ + url: createURL('listVPCs'), + data: { + listAll: true + }, + async: false, + success: function(json) { + vpcs = json.listvpcsresponse.vpc; + } + }); + if (vpcs == null || vpcs.length == 0) { //if there is no VPC in the system + $.extend(data, { + forVpc: false + }); + } + } + + if(!isAdmin()) { //normal user is not aware of the VLANs in the system, so normal user is not allowed to create network with network offerings whose specifyvlan = true + $.extend(data, { + specifyvlan: false + }); + } + + $.ajax({ + url: createURL('listNetworkOfferings'), + data: data, + success: function(json) { + networkOfferingObjs = json.listnetworkofferingsresponse.networkoffering; + args.$select.change(function() { + var $vlan = args.$select.closest('form').find('[rel=vlan]'); + var networkOffering = $.grep( + networkOfferingObjs, function(netoffer) { + return netoffer.id == args.$select.val(); + } + )[0]; + + if (networkOffering.specifyvlan) { + $vlan.css('display', 'inline-block'); + } else { + $vlan.hide(); + } + }); + + args.response.success({ + data: $.map(networkOfferingObjs, function(zone) { + return { + id: zone.id, + description: zone.name + }; + }) + }); + } + }); + } + }, + + vlan: { + label: 'label.vlan', + validation: { + required: true + }, + isHidden: true + }, + + vpcid: { + label: 'label.vpc', + dependsOn: 'networkOfferingId', + select: function(args) { + var networkOfferingObj; + var $form = args.$select.closest('form'); + var data = { + listAll: true, + details: 'min' + }; + + if (args.context.vpc) { + data.id = args.context.vpc[0].id; + } + + $(networkOfferingObjs).each(function(key, value) { + if (value.id == args.networkOfferingId) { + networkOfferingObj = value; + return false; //break each loop + } + }); + + if (networkOfferingObj.forvpc == true) { + args.$select.closest('.form-item').css('display', 'inline-block'); + $.ajax({ + url: createURL('listVPCs'), + data: data, + success: function(json) { + var items = json.listvpcsresponse.vpc; + var data; + if (items != null && items.length > 0) { + data = $.map(items, function(item) { + return { + id: item.id, + description: item.name + } + }); + } + args.response.success({ + data: data + }); + } + }); + $form.find('.form-item[rel=networkDomain]').hide(); + } else { + args.$select.closest('.form-item').hide(); + $form.find('.form-item[rel=networkDomain]').show(); + args.response.success({ + data: null + }); + } + } + }, + tungstenvirtualrouteruuid: { + label: 'label.tungsten', + dependsOn: 'networkOfferingId', + select: function(args) { + var networkOfferingObj; + var $form = args.$select.closest('form'); + var data = { + listAll: true, + details: 'min' + }; + + $(networkOfferingObjs).each(function(key, value) { + if (value.id == args.networkOfferingId) { + networkOfferingObj = value; + return false; //break each loop + } + }); + + if (networkOfferingObj.fortungsten == true) { + args.$select.closest('.form-item').css('display', 'inline-block'); + $.ajax({ + url: createURL('listTungstenVirtualRouters'), + data: data, + success: function(json) { + var items = json.listtungstenvirtualroutersresponse.tungstenVirtualRouter; + var data; + if (items != null && items.length > 0) { + data = $.map(items, function(item) { + return { + id: item.uuid, + description: item.name + } + }); + } + args.response.success({ + data: data + }); + } + }); + $form.find('.form-item[rel=networkDomain]').hide(); + } else { + args.$select.closest('.form-item').hide(); + $form.find('.form-item[rel=networkDomain]').show(); + args.response.success({ + data: null + }); + } + } + }, + externalId: { + label: 'label.guest.externalId' + }, + guestGateway: { + label: 'label.guest.gateway', + docID: 'helpGuestNetworkGateway' + }, + guestNetmask: { + label: 'label.guest.netmask', + docID: 'helpGuestNetworkNetmask' + }, + networkDomain: { + label: 'label.network.domain' + }, + account: { + label: 'label.account', + validation: { + required: true + }, + isHidden: function(args) { + if (isAdmin() || isDomainAdmin()) + return false; + else + return true; + } + } + } + }, + action: function(args) { + var dataObj = { + zoneId: args.data.zoneId, + name: args.data.name, + displayText: args.data.displayText, + networkOfferingId: args.data.networkOfferingId + }; + + if (args.data.guestGateway != null && args.data.guestGateway.length > 0) { + $.extend(dataObj, { + gateway: args.data.guestGateway + }); + } + if (args.data.guestNetmask != null && args.data.guestNetmask.length > 0) { + $.extend(dataObj, { + netmask: args.data.guestNetmask + }); + } + if (args.data.externalId != null && args.data.externalId.length > 0) { + $.extend(dataObj, { + externalid: args.data.externalId + }); + } + if (args.$form.find('.form-item[rel=vpcid]').css("display") != "none") { + $.extend(dataObj, { + vpcid: args.data.vpcid + }); + } + + if (args.$form.find('.form-item[rel=tungstenvirtualrouteruuid]').css("display") != "none") { + $.extend(dataObj, { + tungstenvirtualrouteruuid: args.data.tungstenvirtualrouteruuid + }); + } + + if (args.$form.find('.form-item[rel=vlan]').css('display') != 'none') { + $.extend(dataObj, { + vlan: args.data.vlan + }); + } + + if (args.data.networkDomain != null && args.data.networkDomain.length > 0 && args.$form.find('.form-item[rel=vpcid]').css("display") == "none") { + $.extend(dataObj, { + networkDomain: args.data.networkDomain + }); + } + + if (args.data.domain != null && args.data.domain.length > 0) { + $.extend(dataObj, { + domainid: args.data.domain + }); + if (args.data.account != null && args.data.account.length > 0) { + $.extend(dataObj, { + account: args.data.account + }); + } + } + + $.ajax({ + url: createURL('createNetwork'), + data: dataObj, + success: function(json) { + args.response.success({ + data: json.createnetworkresponse.network + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + messages: { + notification: function() { + return 'label.add.isolated.guest.network'; + } + } + }, + + rootAdminAddGuestNetwork: $.extend({}, addGuestNetworkDialog.def, { + isHeader: true + }), + + AddL2Network: $.extend({}, addL2GuestNetwork.def, { + isHeader: true + }) + + }, + id: 'networks', + preFilter: function(args) { + if (isAdmin() || isDomainAdmin()) { + return [] + } + return ['account'] + }, + fields: { + name: { + label: 'label.name' + }, + type: { + label: 'label.type' + }, + cidr: { + label: 'label.cidr' + }, + ip6cidr: { + label: 'label.ipv6.CIDR' + }, + account: { + label: 'label.account' + }, + zonename: { + label: 'label.zone' + }, + state: { + converter: function(str) { + // For localization + return str; + }, + label: 'label.state', + indicator: { + 'Allocated': 'on', + 'Released': 'off', + 'Destroy': 'off', + 'Shutdown': 'off', + 'Setup': 'on', + 'Implemented': 'on' + } + } + }, + + advSearchFields: { + zoneid: { + label: 'label.zone', + select: function(args) { + $.ajax({ + url: createURL('listZones'), + data: { + listAll: true + }, + success: function(json) { + var zones = json.listzonesresponse.zone ? json.listzonesresponse.zone : []; + + args.response.success({ + data: $.map(zones, function(zone) { + return { + id: zone.id, + description: zone.name + }; + }) + }); + } + }); + } + }, + + domainid: { + label: 'label.domain', + select: function(args) { + if (isAdmin() || isDomainAdmin()) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + success: function(json) { + var array1 = [{ + id: '', + description: '' + }]; + var domains = json.listdomainsresponse.domain; + if (domains != null && domains.length > 0) { + for (var i = 0; i < domains.length; i++) { + array1.push({ + id: domains[i].id, + description: domains[i].path + }); + } + } + array1.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: array1 + }); + } + }); + } else { + args.response.success({ + data: null + }); + } + }, + isHidden: function(args) { + if (isAdmin() || isDomainAdmin()) + return false; + else + return true; + } + }, + + account: { + label: 'label.account', + isHidden: function(args) { + if (isAdmin() || isDomainAdmin()) + return false; + else + return true; + } + }, + tagKey: { + label: 'label.tag.key' + }, + tagValue: { + label: 'label.tag.value' + } + }, + + dataProvider: function(args) { + var data = {}; + listViewDataProvider(args, data); + + if ("routers" in args.context) { + if ("vpcid" in args.context.routers[0]) { + $.extend(data, { + vpcid: args.context.routers[0].vpcid + }); + } else { + if ("guestnetworkid" in args.context.routers[0]) { + $.extend(data, { + id: args.context.routers[0].guestnetworkid + }); + } + } + if ("projectid" in args.context.routers[0]) { + $.extend(data, { + projectid: args.context.routers[0].projectid + }); + } + } + + $.ajax({ + url: createURL('listNetworks'), + data: data, + async: false, + success: function(data) { + args.response.success({ + data: data.listnetworksresponse.network + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + detailView: { + name: 'label.guest.network.details', + viewAll: [{ + path: 'network.ipAddresses', + label: 'label.menu.ipaddresses', + preFilter: function(args) { + if (args.context.networks[0].state == 'Destroyed' || + args.context.networks[0].type == 'L2') + return false; + + return true; + } + }, { + label: 'label.instances', + path: 'instances' + }], + actions: { + edit: { + label: 'label.edit', + messages: { + notification: function(args) { + return 'label.edit.network.details'; + } + }, + preFilter: function(args) { + if (args.context.networks[0].state == 'Destroyed') + return false; + return true; + }, + action: function(args) { + var data = { + id: args.context.networks[0].id, + name: args.data.name, + displaytext: args.data.displaytext + }; + + //args.data.networkdomain is null when networkdomain field is hidden + if (args.data.networkdomain != null && args.data.networkdomain.length > 0 && args.data.networkdomain != args.context.networks[0].networkdomain) { + $.extend(data, { + networkdomain: args.data.networkdomain + }); + } + + var oldcidr; + $.ajax({ + url: createURL("listNetworks&id=" + args.context.networks[0].id + "&listAll=true"), + dataType: "json", + async: false, + success: function(json) { + oldcidr = json.listnetworksresponse.network[0].cidr; + + } + }); + + + if (args.data.cidr != "" && args.data.cidr != oldcidr) { + $.extend(data, { + guestvmcidr: args.data.cidr + }); + } + + //args.data.networkofferingid is null when networkofferingid field is hidden + if (args.data.networkofferingid != null && args.data.networkofferingid != args.context.networks[0].networkofferingid) { + $.extend(data, { + networkofferingid: args.data.networkofferingid + }); + + if (args.context.networks[0].type == "Isolated") { //Isolated network + cloudStack.dialog.confirm({ + message: 'message.confirm.current.guest.CIDR.unchanged', + action: function() { //"Yes" button is clicked + getForcedInfoAndUpdateNetwork(data, args); + }, + cancelAction: function() { //"Cancel" button is clicked + $.extend(data, { + changecidr: true + }); + + getForcedInfoAndUpdateNetwork(data, args); + } + }); + return; + } + } + + $.ajax({ + url: createURL('updateNetwork'), + data: data, + success: function(json) { + var jid = json.updatenetworkresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + var item = json.queryasyncjobresultresponse.jobresult.network; + return { + data: item + }; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + restart: { + label: 'label.restart.network', + preFilter: function(args) { + if (args.context.networks[0].state == 'Destroyed') + return false; + return true; + }, + createForm: { + title: 'label.restart.network', + desc: 'message.restart.network', + preFilter: function(args) { + var zoneObj; + $.ajax({ + url: createURL("listZones&id=" + args.context.networks[0].zoneid), + dataType: "json", + async: false, + success: function(json) { + zoneObj = json.listzonesresponse.zone[0]; + } + }); + args.$form.find('.form-item[rel=cleanup]').find('input').attr('checked', 'checked'); //checked + args.$form.find('.form-item[rel=cleanup]').css('display', 'inline-block'); //shown + args.$form.find('.form-item[rel=makeredundant]').find('input').attr('checked', 'checked'); //checked + args.$form.find('.form-item[rel=makeredundant]').css('display', 'inline-block'); //shown + + if (Boolean(args.context.networks[0].redundantrouter)) { + args.$form.find('.form-item[rel=makeredundant]').hide(); + } else { + args.$form.find('.form-item[rel=makeredundant]').show(); + } + }, + fields: { + cleanup: { + label: 'label.clean.up', + isBoolean: true + }, + makeredundant: { + label: 'label.make.redundant', + isBoolean: true + } + } + }, + messages: { + notification: function(args) { + return 'label.restart.network'; + } + }, + action: function(args) { + $.ajax({ + url: createURL("restartNetwork"), + data: { + id: args.context.networks[0].id, + cleanup: (args.data.cleanup == "on"), + makeredundant: (args.data.makeredundant == "on") + }, + dataType: "json", + async: true, + success: function(json) { + var jid = json.restartnetworkresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.network; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + remove: { + label: 'label.action.delete.network', + preFilter: function(args) { + if (args.context.networks[0].state == 'Destroyed') + return false; + return true; + }, + messages: { + confirm: function(args) { + return 'message.action.delete.network'; + }, + isWarning: true, + notification: function(args) { + return 'label.action.delete.network'; + } + }, + action: function(args) { + $.ajax({ + url: createURL("deleteNetwork&id=" + args.context.networks[0].id), + dataType: "json", + async: true, + success: function(json) { + var jid = json.deletenetworkresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + + tabFilter: function(args) { + var networkHavingELB = false; + var hasNetworkACL = false; + var hasSRXFirewall = false; + var isVPC = false; + var isAdvancedSGZone = false; + var hiddenTabs = []; + var isSharedNetwork; + + var thisNetwork = args.context.networks[0]; + if (thisNetwork.vpcid != null) { + isVPC = true; + } + if (thisNetwork.type == 'Shared') { + isSharedNetwork = true; + } + + $(thisNetwork.service).each(function() { + var thisService = this; + + if (thisService.name == 'NetworkACL') { + hasNetworkACL = true; + } else if (thisService.name == "Lb") { + $(thisService.capability).each(function() { + if (this.name == "ElasticLb" && this.value == "true") { + networkHavingELB = true; + } + }); + } + + if (thisService.name == 'Firewall') { + $(thisService.provider).each(function() { + if (this.name == 'JuniperSRX') { + hasSRXFirewall = true; + + return false; + } + + return true; + }); + } + }); + + // Get zone data + $.ajax({ + url: createURL('listZones'), + data: { + id: args.context.networks[0].zoneid + }, + async: false, + success: function(json) { + var zone = json.listzonesresponse.zone[0]; + + isAdvancedSGZone = zone.securitygroupsenabled; + } + }); + + if (isVPC || isAdvancedSGZone || isSharedNetwork) { + hiddenTabs.push('egressRules'); + } + + if (!isAdmin()) { + hiddenTabs.push("virtualRouters"); + } + + return hiddenTabs; + }, + + isMaximized: true, + tabs: { + details: { + title: 'label.details', + preFilter: function(args) { + var hiddenFields = []; + var zone; + + $.ajax({ + url: createURL('listZones'), + data: { + id: args.context.networks[0].zoneid + }, + async: false, + success: function(json) { + zone = json.listzonesresponse.zone[0]; + } + }); + + if (zone.networktype == "Basic") { + hiddenFields.push("account"); + hiddenFields.push("gateway"); + hiddenFields.push("vlan"); + hiddenFields.push("cidr"); + //hiddenFields.push("netmask"); + } + + if (args.context.networks[0].type == "Isolated") { + hiddenFields.push("networkofferingdisplaytext"); + hiddenFields.push("networkdomaintext"); + hiddenFields.push("gateway"); + hiddenFields.push("networkofferingname"); + //hiddenFields.push("netmask"); + } else { //selectedGuestNetworkObj.type == "Shared" + hiddenFields.push("networkofferingid"); + hiddenFields.push("networkdomain"); + } + + if (!isAdmin()) { + hiddenFields.push("vlan"); + } + + return hiddenFields; + }, + + fields: [{ + name: { + label: 'label.name', + isEditable: true + } + }, { + id: { + label: 'label.id' + }, + zonename: { + label: 'label.zone' + }, + displaytext: { + label: 'label.description', + isEditable: true + }, + type: { + label: 'label.type' + }, + state: { + label: 'label.state' + }, + + vpcid: { + label: 'label.vpc.id', + converter: function(args) { + if (args != null) + return args; + else + return _l('label.na'); + } + }, + + ispersistent: { + label: 'label.persistent', + converter: cloudStack.converters.toBooleanText + + }, + restartrequired: { + label: 'label.restart.required', + converter: function(booleanValue) { + if (booleanValue == true) + return "Yes"; + else if (booleanValue == false) + return "No"; + } + }, + vlan: { + label: 'label.vnet.id' + }, + + broadcasturi: { + label: 'label.broadcasturi' + }, + + networkofferingid: { + label: 'label.network.offering', + isEditable: true, + select: function(args) { + if (args.context.networks[0].type == 'Shared') { //Shared network is not allowed to upgrade to a different network offering + args.response.success({ + data: [] + }); + return; + } + + if (args.context.networks[0].state == 'Destroyed') { + args.response.success({ + data: [] + }); + return; + } + + var items = []; + $.ajax({ + url: createURL("listNetworkOfferings&networkid=" + args.context.networks[0].id), + dataType: "json", + async: false, + success: function(json) { + var networkOfferingObjs = json.listnetworkofferingsresponse.networkoffering; + $(networkOfferingObjs).each(function() { + items.push({ + id: this.id, + description: this.displaytext + }); + }); + } + }); + + //include currently selected network offeirng to dropdown + items.push({ + id: args.context.networks[0].networkofferingid, + description: args.context.networks[0].networkofferingdisplaytext + }); + + args.response.success({ + data: items + }); + } + }, + + gateway: { + label: 'label.gateway' + }, + + //netmask: { label: 'label.netmask' }, + cidr: { + label: 'label.cidr', + isEditable: true + }, + + networkcidr: { + label: 'label.network.cidr' + }, + + ip6gateway: { + label: 'label.ipv6.gateway' + }, + + ip6cidr: { + label: 'label.ipv6.CIDR' + }, + + + reservediprange: { + label: 'label.reserved.ip.range' + }, + + redundantrouter: { + label: 'label.redundant.router', + converter: function(booleanValue) { + if (booleanValue == true) { + return "Yes"; + } + return "No"; + } + }, + + networkdomaintext: { + label: 'label.network.domain.text' + }, + + networkdomain: { + label: 'label.network.domain', + isEditable: true + }, + + domain: { + label: 'label.domain' + }, + account: { + label: 'label.account' + } + }], + + tags: cloudStack.api.tags({ + resourceType: 'Network', + contextId: 'networks' + }), + + + dataProvider: function(args) { + $.ajax({ + url: createURL("listNetworks&id=" + args.context.networks[0].id + "&listAll=true"), //pass "&listAll=true" to "listNetworks&id=xxxxxxxx" for now before API gets fixed. + data: { + listAll: true + }, + dataType: "json", + async: true, + success: function(json) { + var jsonObj = json.listnetworksresponse.network[0]; + addExtraPropertiesToGuestNetworkObject(jsonObj); + + $(window).trigger('cloudStack.module.sharedFunctions.addExtraProperties', { + obj: jsonObj, + objType: "Network" + }); + + args.response.success({ + actionFilter: cloudStack.actionFilter.guestNetwork, + data: jsonObj + }); + } + }); + } + }, + + egressRules: { + title: 'label.egress.rules', + custom: function(args) { + var context = args.context; + var isConfigRulesMsgShown = false; + + return $('
').multiEdit({ + context: context, + noSelect: true, + noHeaderActionsColumn: true, + fields: { + 'cidrlist': { + edit: true, + label: 'label.cidr.list', + isOptional: true + }, + 'destcidrlist': { + edit: true, + label: 'label.cidr.destination.list', + isOptional: true + }, + 'protocol': { + label: 'label.protocol', + select: function(args) { + args.$select.change(function() { + var $inputs = args.$form.find('th, td'); + var $icmpFields = $inputs.filter(function() { + var name = $(this).attr('rel'); + + return $.inArray(name, [ + 'icmptype', + 'icmpcode' + ]) > -1; + }); + var $otherFields = $inputs.filter(function() { + var name = $(this).attr('rel'); + + return name != 'cidrlist' && + name != 'destcidrlist' && + name != 'icmptype' && + name != 'icmpcode' && + name != 'protocol' && + name != 'add-rule'; + }); + + if ($(this).val() == 'icmp') { + $icmpFields.show(); + $otherFields.hide(); + } else if ($(this).val() == 'all') { + $icmpFields.hide(); + $otherFields.hide(); + } else { + $icmpFields.hide(); + $otherFields.show(); + } + }); + + args.response.success({ + data: [{ + name: 'tcp', + description: 'TCP' + }, { + name: 'udp', + description: 'UDP' + }, { + name: 'icmp', + description: 'ICMP' + }, { + name: 'all', + description: 'All' + }] + }); + } + }, + 'startport': { + edit: true, + label: 'label.start.port', + isOptional: true + }, + 'endport': { + edit: true, + label: 'label.end.port', + isOptional: true + }, + 'icmptype': { + edit: true, + label: 'ICMP.type', + isHidden: true, + isOptional: true + }, + 'icmpcode': { + edit: true, + label: 'ICMP.code', + isHidden: true, + isOptional: true + }, + 'add-rule': { + label: 'label.add', + addButton: true + } + }, + add: { + label: 'label.add', + action: function(args) { + var data = { + protocol: args.data.protocol, + cidrlist: args.data.cidrlist, + destcidrlist: args.data.destcidrlist, + networkid: args.context.networks[0].id + }; + + if (args.data.icmptype && args.data.icmpcode) { // ICMP + $.extend(data, { + icmptype: args.data.icmptype, + icmpcode: args.data.icmpcode + }); + } else { // TCP/UDP + $.extend(data, { + startport: args.data.startport, + endport: args.data.endport + }); + } + + $.ajax({ + url: createURL('createEgressFirewallRule'), + data: data, + dataType: 'json', + async: true, + success: function(json) { + var jobId = json.createegressfirewallruleresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobId + }, + notification: { + label: 'label.add.egress.rule', + poll: pollAsyncJobResult + } + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + }, + actions: { + destroy: { + label: 'label.remove.rule', + action: function(args) { + $.ajax({ + url: createURL('deleteEgressFirewallRule'), + data: { + id: args.context.multiRule[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + var jobID = data.deleteegressfirewallruleresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobID + }, + notification: { + label: 'label.remove.egress.rule', + poll: pollAsyncJobResult + } + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + }, + ignoreEmptyFields: true, + dataProvider: function(args) { + $.ajax({ + url: createURL('listEgressFirewallRules'), + data: { + listAll: true, + networkid: args.context.networks[0].id + }, + dataType: 'json', + async: false, + success: function(json) { + var response = json.listegressfirewallrulesresponse.firewallrule ? + json.listegressfirewallrulesresponse.firewallrule : []; + + if (response.length > 0) { + isConfigRulesMsgShown = true; + } + args.response.success({ + data: $.map(response, function(rule) { + if (rule.protocol == 'all') { + $.extend(rule, { + startport: 'All', + endport: 'All' + }); + } else if (rule.protocol == 'tcp' || rule.protocol == 'udp') { + if (!rule.startport) { + rule.startport = ' '; + } + + if (!rule.endport) { + rule.endport = ' '; + } + } + if(!rule.destcidrlist){ + rule.destcidrlist = ' '; + } + return rule; + }) + }); + } + }); + + if (!isConfigRulesMsgShown) { + isConfigRulesMsgShown = true; + $.ajax({ + url: createURL('listNetworkOfferings'), + data: { + id: args.context.networks[0].networkofferingid + }, + dataType: 'json', + async: true, + success: function(json) { + var response = json.listnetworkofferingsresponse.networkoffering ? + json.listnetworkofferingsresponse.networkoffering[0] : null; + + if (response != null) { + if (response.egressdefaultpolicy == true) { + cloudStack.dialog.notice({ + message: _l('message.configure.firewall.rules.block.traffic') + }); + } else { + cloudStack.dialog.notice({ + message: _l('message.configure.firewall.rules.allow.traffic') + }); + } + } + } + }); + } + } + }); + } + }, + + virtualRouters: { + title: "label.virtual.appliances", + listView: cloudStack.sections.system.subsections.virtualRouters.sections.routerNoGroup.listView + } + } + } + } + }, + secondaryNicIps: { + title: 'label.menu.ipaddresses', + listView: { + id: 'secondaryNicIps', + label: 'label.ips', + fields: { + virtualmachinedisplayname: { + label: 'label.vm.name' + }, + ipaddress: { + label: 'label.ips', + converter: function(text, item) { + if (item.issourcenat) { + return text + ' [' + _l('label.source.nat') + ']'; + } + + return text; + } + } + }, + actions: { + add: { + label: 'label.acquire.new.secondary.ip', + addRow: 'true', + createForm: { + title: 'label.acquire.new.secondary.ip', + desc: 'message.acquire.ip.nic', + fields: { + ipaddress: { + label: 'label.ip.address', + validation: { + required: false, + ipv4AndIpv6AddressValidator: true + } + } + } + }, + messages: { + notification: function(args) { + return _l('label.acquire.new.secondary.ip'); + } + }, + action: function(args) { + var dataObj = { + nicId: args.context.nics[0].id + }; + + if (args.data.ipaddress) { + dataObj.ipaddress = args.data.ipaddress; + } + + $.ajax({ + url: createURL('addIpToNic'), + data: dataObj, + success: function(json) { + args.response.success({ + _custom: { + getUpdatedItem: function(data) { + return $.extend( + data.queryasyncjobresultresponse.jobresult.nicsecondaryip, { + zoneid: args.context.instances[0].zoneid, + virtualmachinedisplayname: args.context.instances[0].displayname ? args.context.instances[0].displayname : args.context.instances[0].name + } + ); + }, + jobId: json.addiptovmnicresponse.jobid + } + }); + } + }); + }, + + notification: { + poll: pollAsyncJobResult + } + } + }, + + dataProvider: function(args) { + var data = {}; + + if (args.filterBy.search.value != null) { + data.keyword = args.filterBy.search.value; + } + + $.ajax({ + url: createURL('listNics'), + data: { + nicId: args.context.nics[0].id, + virtualmachineid: args.context.instances[0].id, + keyword: args.filterBy.search.value + }, + success: function(json) { + var ips = json.listnicsresponse.nic ? json.listnicsresponse.nic[0].secondaryip : []; + + args.response.success({ + data: $(ips).map(function(index, ip) { + return $.extend(ip, { + zoneid: args.context.instances[0].zoneid, + virtualmachinedisplayname: args.context.instances[0].displayname ? args.context.instances[0].displayname : args.context.instances[0].name + }); + }) + }); + } + }); + }, + + // Detail view + detailView: { + name: 'Secondary IP address detail', + actions: { + remove: { + label: 'label.action.release.ip', + action: function(args) { + $.ajax({ + url: createURL('removeIpFromNic'), + data: { + id: args.context.secondaryNicIps[0].id + }, + success: function(json) { + args.response.success({ + _custom: { + jobId: json.removeipfromnicresponse.jobid + } + }); + } + }); + }, + messages: { + confirm: function(args) { + return 'message.action.release.ip'; + }, + notification: function(args) { + return 'label.action.release.ip'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.details', + fields: [{ + ipaddress: { + label: 'label.ip' + } + }, { + id: { + label: 'label.id' + }, + virtualmachinedisplayname: { + label: 'label.vm.name' + }, + zonename: { + label: 'label.zone.name' + } + }], + + dataProvider: function(args) { + $.ajax({ + url: createURL('listNics'), + data: { + nicId: args.context.nics[0].id, + virtualmachineid: args.context.instances[0].id + }, + success: function(json) { + var ips = json.listnicsresponse.nic[0].secondaryip + + args.response.success({ + data: $.grep($(ips).map(function(index, ip) { + return $.extend(ip, { + zonename: args.context.instances[0].zonename, + virtualmachinedisplayname: args.context.instances[0].displayname + }); + }), function(ip) { + return ip.ipaddress == args.context.secondaryNicIps[0].ipaddress; + })[0] + }); + } + }); + } + } + } + } + } + }, + ipAddresses: { + type: 'select', + title: 'label.menu.ipaddresses', + listView: { + id: 'ipAddresses', + label: 'label.ips', + preFilter: function(args) { + if (isAdmin()) { + return ['account'] + } + return [] + }, + fields: { + ipaddress: { + label: 'label.ips', + converter: function(text, item) { + if (item.issourcenat) { + return text + ' [' + _l('label.source.nat') + ']'; + } + + return text; + } + }, + associatednetworkname: { + label: 'label.network' + }, + virtualmachinedisplayname: { + label: 'label.vm.name' + }, + account: { + label: 'label.account' + }, + zonename: { + label: 'label.zone' + }, + state: { + converter: function(str) { + // For localization + return str; + }, + label: 'label.state', + indicator: { + 'Allocated': 'on', + 'Released': 'off' + } + } + }, + actions: { + add: { + label: 'label.acquire.new.ip', + addRow: 'true', + preFilter: function(args) { + var zoneObj; + var dataObj = {}; + + if ('vpc' in args.context) { //from VPC section + $.extend(dataObj, { + id: args.context.vpc[0].zoneid + }); + } else if ('networks' in args.context) { //from Guest Network section + $.extend(dataObj, { + id: args.context.networks[0].zoneid + }); + } + + $.ajax({ + url: createURL('listZones'), + data: dataObj, + async: false, + success: function(json) { + zoneObj = json.listzonesresponse.zone[0]; + } + }); + + if (zoneObj.networktype == 'Advanced' && zoneObj.securitygroupsenabled) { + return false; + } + + if (zoneObj.networktype == 'Basic') { + var havingEIP = false, + havingELB = false; + + var services = args.context.networks[0].service; + if(services != null) { + for(var i = 0; i < services.length; i++) { + var thisService = services[i]; + var capabilities = thisService.capability; + if (thisService.name == "StaticNat") { + if(capabilities != null) { + for(var k = 0; k < capabilities.length; k++) { + if (capabilities[k].name == "ElasticIp" && capabilities[k].value == "true") { + havingEIP = true; + break; + } + } + } + } else if (thisService.name == "Lb") { + if(capabilities != null) { + for(var k = 0; k < capabilities.length; k++) { + if (capabilities[k].name == "ElasticLb" && capabilities[k].value == "true") { + havingELB = true; + break; + } + } + } + } + } + } + + if (havingEIP != true || havingELB != true) { //not EIP-ELB + return false; //acquire new IP is not allowed in non-EIP-ELB basic zone + } + } + + //*** from Guest Network section *** + if (!('vpc' in args.context)) { + if (args.context.networks[0].vpcid == null) { //Guest Network section > non-VPC network, show Acquire IP button + return true; + } else { //Guest Network section > VPC network, hide Acquire IP button + return false; + } + } + //*** from VPC section *** + else { //'vpc' in args.context //args.context.networks[0] has only one property => name: 'Router' + return true; //VPC section, show Acquire IP button + } + }, + messages: { + notification: function(args) { + return 'label.acquire.new.ip'; + } + }, + createForm: { + title: 'label.acquire.new.ip', + desc: 'Please confirm that you want to acquire new IP', + preFilter: function(args) { + $.ajax({ + url: createURL('listRegions'), + success: function(json) { + var selectedRegionName = $(".region-switcher .title").text(); + if ( selectedRegionName == undefined || selectedRegionName.length == 0) { + selectedRegionName = "Local"; + } + var items = json.listregionsresponse.region; + if(items != null) { + for(var i = 0; i < items.length; i++) { + if(items[i].name == selectedRegionName) { + if(items[i].portableipserviceenabled == true) { + args.$form.find('.form-item[rel=isportable]').css('display', 'inline-block'); + } else { + args.$form.find('.form-item[rel=isportable]').hide(); + } + break; + } + } + } + } + }); + }, + fields: { + isportable: { + label: 'label.cross.zones', + select: function(args) { + var items = []; + items.push({ + id: "false", + description: _l('label.no') + }); + items.push({ + id: "true", + description: _l('label.yes') + }); + args.response.success({ + data: items + }); + }, + isHidden: true + }, + ipaddress: { + label: 'label.ip.address', + select: function(args) { + var data = { + forvirtualnetwork : true, + allocatedonly: false + }; + if ('vpc' in args.context) { //from VPC section + $.extend(data, { + zoneid: args.context.vpc[0].zoneid, + domainid: args.context.vpc[0].domainid, + account: args.context.vpc[0].account + }); + } else if ('networks' in args.context) { //from Guest Network section + $.extend(data, { + zoneid: args.context.networks[0].zoneid, + domainid: args.context.networks[0].domainid, + account: args.context.networks[0].account + }); + } + $.ajax({ + url: createURL('listPublicIpAddresses'), + data: data, + success: function(json) { + var ips = json.listpublicipaddressesresponse.publicipaddress; + var items = []; + $(ips).each(function() { + if (this.state == "Free") { + items.push({ + id: this.ipaddress, + description: this.ipaddress + }); + } + }); + args.response.success({ + data: items + }); + } + }) + } + } + } + }, + action: function(args) { + var dataObj = {}; + if (args.$form.find('.form-item[rel=isportable]').css("display") != "none") { + $.extend(dataObj, { + isportable: args.data.isportable + }); + } + + if ('vpc' in args.context) { //from VPC section + $.extend(dataObj, { + vpcid: args.context.vpc[0].id + }); + } else if ('networks' in args.context) { //from Guest Network section + $.extend(dataObj, { + networkid: args.context.networks[0].id + }); + + if (args.context.networks[0].type == "Shared" && !args.context.projects) { + $.extend(dataObj, { + domainid: g_domainid, + account: g_account + }); + } + } + + if (args.data.ipaddress != null && args.data.ipaddress.length > 0) { + $.extend(dataObj, { + ipaddress: args.data.ipaddress + }); + } + $.ajax({ + url: createURL('associateIpAddress'), + data: dataObj, + success: function(data) { + args.response.success({ + _custom: { + jobId: data.associateipaddressresponse.jobid, + getUpdatedItem: function(data) { + var newIP = data.queryasyncjobresultresponse.jobresult.ipaddress; + return $.extend(newIP, { + state: 'Allocated' + }); + }, + getActionFilter: function() { + return actionFilters.ipAddress; + } + } + }); + }, + + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + + notification: { + poll: pollAsyncJobResult + } + } + }, + + dataProvider: function(args) { + var items = []; + var data = {}; + listViewDataProvider(args, data); + if (args.context.networks) { + $.extend(data, { + associatedNetworkId: args.context.networks[0].id + }); + } + if ("vpc" in args.context) { + $.extend(data, { + vpcid: args.context.vpc[0].id + }); + } + + $.ajax({ + url: createURL('listPublicIpAddresses'), + data: $.extend({}, data, { + forvirtualnetwork: true //IPs are allocated on public network + }), + dataType: "json", + async: false, + success: function(json) { + var ips = json.listpublicipaddressesresponse.publicipaddress; + if(ips != null) { + for(var i = 0; i < ips.length; i++) { + getExtaPropertiesForIpObj(ips[i], args); + items.push(ips[i]); + } + } + } + }); + + if (g_supportELB == "guest") { + $.ajax({ + url: createURL('listPublicIpAddresses'), + data: $.extend({}, data, { + forvirtualnetwork: false, // ELB IPs are allocated on guest network + forloadbalancing: true + }), + dataType: "json", + async: false, + success: function(json) { + var ips = json.listpublicipaddressesresponse.publicipaddress; + if(ips != null) { + for(var i = 0; i < ips.length; i++) { + getExtaPropertiesForIpObj(ips[i], args); + items.push(ips[i]); + } + } + } + }); + } + + args.response.success({ + actionFilter: actionFilters.ipAddress, + data: items + }); + }, + + // Detail view + detailView: { + name: 'IP address detail', + tabFilter: function(args) { + var item = args.context.ipAddresses[0]; + + var disabledTabs = []; + var ipAddress = args.context.ipAddresses[0]; + var disableVpn = false, + disableIpRules = false; + + if (!ipAddress.vpnenabled) { + disableVpn = true; + } + + if (ipAddress.issystem == true) { + disableVpn = true; + + if (ipAddress.isstaticnat == true || ipAddress.virtualmachineid != null) { + disableIpRules = true; + } + } + + if (ipAddress.vpcid != null && ipAddress.issourcenat) { //don't show Configuration(ipRules) tab on VPC sourceNAT IP + disableIpRules = true; + } + + if (('vpc' in args.context) == false && ipAddress.vpcid != null) { //from Guest Network section, don't show Configuration(ipRules) tab on VPC IP + disableIpRules = true; + } + + if (disableVpn) + disabledTabs.push('vpn'); + if (disableIpRules) + disabledTabs.push('ipRules'); + + return disabledTabs; + }, + actions: { + enableVPN: { + label: 'label.enable.vpn', + action: function(args) { + $.ajax({ + url: createURL('createRemoteAccessVpn'), + data: { + publicipid: args.context.ipAddresses[0].id, + domainid: args.context.ipAddresses[0].domainid, + account: args.context.ipAddresses[0].account + }, + dataType: 'json', + async: true, + success: function(data) { + args.response.success({ + _custom: { + getUpdatedItem: function(json) { + var vpnenabledAndRunning = false; + if (json.queryasyncjobresultresponse.jobresult.remoteaccessvpn.state == "Running") { + vpnenabledAndRunning = true; + } + + return { + remoteaccessvpn: json.queryasyncjobresultresponse.jobresult.remoteaccessvpn, + vpnenabled: vpnenabledAndRunning + }; + }, + getActionFilter: function() { + return actionFilters.ipAddress; + }, + jobId: data.createremoteaccessvpnresponse.jobid + } + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + messages: { + confirm: function(args) { + return 'message.enable.vpn'; + }, + notification: function(args) { + return 'label.enable.vpn'; + }, + complete: function(args) { + var msg; + if (args.remoteaccessvpn.state == "Running") { + msg = _l('message.enabled.vpn') + ' ' + args.remoteaccessvpn.publicip + '.' + '
' + _l('message.enabled.vpn.ip.sec') + '
' + args.remoteaccessvpn.presharedkey; + } else { + msg = _l('message.network.remote.access.vpn.configuration'); + } + return msg; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disableVPN: { + label: 'label.disable.vpn', + action: function(args) { + $.ajax({ + url: createURL('deleteRemoteAccessVpn'), + data: { + publicipid: args.context.ipAddresses[0].id, + domainid: args.context.ipAddresses[0].domainid + }, + dataType: 'json', + async: true, + success: function(data) { + args.response.success({ + _custom: { + getUpdatedItem: function(data) { + return { + vpnenabled: false + }; + }, + getActionFilter: function() { + return actionFilters.ipAddress; + }, + jobId: data.deleteremoteaccessvpnresponse.jobid + } + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + messages: { + confirm: function(args) { + return 'message.disable.vpn'; + }, + notification: function(args) { + return 'label.disable.vpn'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + enableStaticNAT: { + label: 'label.action.enable.static.NAT', + + action: { + noAdd: true, + custom: cloudStack.uiCustom.enableStaticNAT({ + tierSelect: function(args) { + if ('vpc' in args.context) { //from VPC section + args.$tierSelect.show(); //show tier dropdown + + $.ajax({ //populate tier dropdown + url: createURL("listNetworks"), + async: false, + data: { + vpcid: args.context.vpc[0].id, + //listAll: true, //do not pass listAll to listNetworks under VPC + domainid: args.context.vpc[0].domainid, + account: args.context.vpc[0].account, + supportedservices: 'StaticNat' + }, + success: function(json) { + var networks = json.listnetworksresponse.network; + var items = [{ + id: -1, + description: 'Please select a tier' + }]; + $(networks).each(function() { + items.push({ + id: this.id, + description: this.displaytext + }); + }); + args.response.success({ + data: items + }); + } + }); + } else { //from Guest Network section + args.$tierSelect.hide(); + } + + args.$tierSelect.change(function() { + args.$tierSelect.closest('.list-view').listView('refresh'); + }); + args.$tierSelect.closest('.list-view').listView('refresh'); + }, + + listView: $.extend(true, {}, cloudStack.sections.instances, { + listView: { + advSearchFields: null, // Not supported in dialogs right now due to display issues + filters: false, + subselect: { + label: 'label.use.vm.ip', + dataProvider: singleVmSecondaryIPSubselect + }, + dataProvider: function(args) { + var data = { + page: args.page, + pageSize: pageSize, + listAll: true + }; + + if (args.filterBy.search.value) { + data.keyword = args.filterBy.search.value; + } + + var $tierSelect = $(".ui-dialog-content").find('.tier-select select'); + + // if $tierSelect is not initialized, return; tierSelect() will refresh listView and come back here later + if ($tierSelect.length == 0) { + args.response.success({ + data: null + }); + return; + } + + // if no tier is selected + if ($tierSelect.val() == '-1') { + args.response.success({ + data: null + }); + return; + } + + if ('vpc' in args.context) { + $.extend(data, { + networkid: $tierSelect.val(), + vpcid: args.context.vpc[0].id + }); + $.extend(args.context, { + networkid: $tierSelect.val(), + vpcid: args.context.vpc[0].id + }); + } else if ('networks' in args.context && !args.context.ipAddresses[0].isportable) { + $.extend(data, { + networkid: args.context.networks[0].id + }); + } + + if (!args.context.projects) { + $.extend(data, { + account: args.context.ipAddresses[0].account, + domainid: args.context.ipAddresses[0].domainid + }); + } + + $.ajax({ + url: createURL('listVirtualMachines'), + data: data, + dataType: 'json', + async: true, + success: function(data) { + args.response.success({ + data: $.grep( + data.listvirtualmachinesresponse.virtualmachine ? + data.listvirtualmachinesresponse.virtualmachine : [], + function(instance) { + return $.inArray(instance.state, [ + 'Destroyed', 'Expunging' + ]) == -1; + } + ) + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + } + }), + action: function(args) { + var data = { + ipaddressid: args.context.ipAddresses[0].id, + virtualmachineid: args.context.instances[0].id + }; + + if (args.context.ipAddresses[0].isportable) { + var subselect = args._subselect.split(','); + var networkid = subselect[0]; + var vmguestip = subselect[1]; + + data.networkid = subselect[0]; + + if (parseInt(vmguestip) !== -1) { + data.vmguestip = vmguestip; + } + } else if (args._subselect && args._subselect != -1) { + data.vmguestip = args._subselect; + } + + if ('vpc' in args.context) { + if (args.tierID == '-1') { + args.response.error('Tier is required'); + return; + } + $.extend(data, { + networkid: args.tierID + }); + } + + $.ajax({ + url: createURL('enableStaticNat'), + data: data, + dataType: 'json', + async: true, + success: function(data) { + args.response.success({}); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }) + }, + messages: { + notification: function(args) { + return 'label.action.enable.static.NAT'; + } + }, + notification: { + poll: function(args) { + args.complete({ + data: { + isstaticnat: true + } + }); + + if (args._custom.$detailView.is(':visible')) { + ipChangeNotice(); + } + } + } + }, + disableStaticNAT: { + label: 'label.action.disable.static.NAT', + action: function(args) { + $.ajax({ + url: createURL('disableStaticNat'), + data: { + ipaddressid: args.context.ipAddresses[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + args.response.success({ + _custom: { + jobId: data.disablestaticnatresponse.jobid, + getUpdatedItem: function() { + return { + isstaticnat: false, + virtualmachinedisplayname: "" + }; + }, + getActionFilter: function() { + return function(args) { + return ['enableStaticNAT']; + }; + }, + onComplete: function(args, _custom) { + if (_custom.$detailView.is(':visible')) { + ipChangeNotice(); + } + } + } + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + messages: { + confirm: function(args) { + return 'message.action.disable.static.NAT'; + }, + notification: function(args) { + return 'label.action.disable.static.NAT'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + remove: { + label: 'label.action.release.ip', + action: function(args) { + $.ajax({ + url: createURL('disassociateIpAddress'), + data: { + id: args.context.ipAddresses[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + args.response.success({ + _custom: { + jobId: data.disassociateipaddressresponse.jobid, + getActionFilter: function() { + return function(args) { + var allowedActions = ['enableStaticNAT']; + + return allowedActions; + }; + }, + getUpdatedItem: function(args) { + return { + state: 'Released' + }; + }, + onComplete: function() { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + messages: { + confirm: function(args) { + return 'message.action.release.ip'; + }, + notification: function(args) { + return 'label.action.release.ip'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.details', + preFilter: function(args) { + var hiddenFields = []; + var zoneObj; + $.ajax({ + url: createURL("listZones&id=" + args.context.ipAddresses[0].zoneid), + dataType: "json", + async: false, + success: function(json) { + zoneObj = json.listzonesresponse.zone[0]; + } + }); + if (zoneObj.networktype == "Advanced") { + hiddenFields.push("issystem"); + hiddenFields.push("purpose"); + } + + if (!isAdmin()) { + hiddenFields.push("vlanname"); + } + return hiddenFields; + }, + fields: [{ + ipaddress: { + label: 'label.ip' + } + }, { + isportable: { + label: 'label.cross.zones', + converter: function(data) { + return data ? _l('label.yes') : _l('label.no'); + } + }, + id: { + label: 'label.id' + }, + associatednetworkid: { + label: 'label.associated.network.id' + }, + associatednetworkname: { + label: 'label.network.name' + }, + state: { + label: 'label.state' + }, + networkid: { + label: 'label.network.id' + }, + issourcenat: { + label: 'label.source.nat', + converter: cloudStack.converters.toBooleanText + }, + isstaticnat: { + label: 'label.static.nat', + converter: cloudStack.converters.toBooleanText + }, + vmipaddress: { + label: 'label.vm.ip' + }, + issystem: { + label: 'label.is.system', + converter: cloudStack.converters.toBooleanText + }, //(basic zone only) + purpose: { + label: 'label.purpose' + }, //(basic zone only) When an IP is system-generated, the purpose it serves can be Lb or static nat. + virtualmachinedisplayname: { + label: 'label.vm.name' + }, + domain: { + label: 'label.domain' + }, + account: { + label: 'label.account' + }, + zonename: { + label: 'label.zone' + }, + vlanname: { + label: 'label.vlan.only' + } + }], + + tags: cloudStack.api.tags({ + resourceType: 'PublicIpAddress', + contextId: 'ipAddresses' + }), + + dataProvider: function(args) { + var items = args.context.ipAddresses; + + $.ajax({ + url: createURL('listPublicIpAddresses'), + data: { + id: args.context.ipAddresses[0].id + }, + dataType: "json", + async: true, + success: function(json) { + var ipObj = json.listpublicipaddressesresponse.publicipaddress[0]; + getExtaPropertiesForIpObj(ipObj, args); + + var network = $.grep( + args.context.vpc ? + args.context.vpc[0].network : args.context.networks, + function(network) { + return network.id = ipObj.associatednetworkid; + })[0]; + + args.response.success({ + actionFilter: actionFilters.ipAddress, + data: ipObj + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }, + + ipRules: { //Configuration tab + title: 'label.configuration', + custom: cloudStack.ipRules({ + preFilter: function(args) { + var disallowedActions = []; + if (args.context.ipAddresses[0].isstaticnat) + disallowedActions.push("nonStaticNATChart"); //tell ipRules widget to show staticNAT chart instead of non-staticNAT chart. + + var havingFirewallService = false; + var havingPortForwardingService = false; + var havingLbService = false; + var havingVpnService = false; + + if (!('vpc' in args.context)) { //from Guest Network section + var services = args.context.networks[0].service; + if(services != null) { + for(var i = 0; i < services.length; i++) { + var thisService = services[i]; + if (thisService.name == "Firewall") + havingFirewallService = true; + if (thisService.name == "PortForwarding") + havingPortForwardingService = true; + if (thisService.name == "Lb") + havingLbService = true; + if (thisService.name == "Vpn") + havingVpnService = true; + } + } + } else { //from VPC section + //a VPC network from Guest Network section or from VPC section + // Firewall is not supported in IP from VPC section + // (because ACL has already supported in tier from VPC section) + havingFirewallService = false; + disallowedActions.push("firewall"); + + havingVpnService = false; //VPN is not supported in IP from VPC section + + if (args.context.ipAddresses[0].associatednetworkid == null) { //IP is not associated with any tier yet + havingPortForwardingService = true; + havingLbService = true; + } else { //IP is associated with a tier + $.ajax({ + url: createURL('listNetworks'), + data: { + listAll: true, + id: args.context.ipAddresses[0].associatednetworkid + }, + async: false, + success: function(json) { + var networkObj = json.listnetworksresponse.network[0]; + var services = networkObj.service; + if(services != null) { + for(var i = 0; i < services.length; i++) { + if (services[i].name == "PortForwarding") + havingPortForwardingService = true; + if (services[i].name == "Lb") + havingLbService = true; + } + } + + if (networkObj.networkofferingconservemode == false) { + /* + (1) If IP is SourceNat, no StaticNat/VPN/PortForwarding/LoadBalancer can be enabled/added. + */ + if (args.context.ipAddresses[0].issourcenat) { + if (havingFirewallService == false) { //firewall is not supported in IP from VPC section (because ACL has already supported in tier from VPC section) + disallowedActions.push("firewall"); + } + + disallowedActions.push("portForwarding"); + disallowedActions.push("loadBalancing"); + } + + /* + (2) If IP is non-SourceNat, show StaticNat/VPN/PortForwarding/LoadBalancer at first. + 1. Once StaticNat is enabled, hide VPN/PortForwarding/LoadBalancer. + 2. If VPN service is supported (i.e. IP comes from Guest Network section, not from VPC section), once VPN is enabled, hide StaticNat/PortForwarding/LoadBalancer. + 3. Once a PortForwarding rule is added, hide StaticNat/VPN/LoadBalancer. + 4. Once a LoadBalancer rule is added, hide StaticNat/VPN/PortForwarding. + */ + else { //args.context.ipAddresses[0].issourcenat == false + if (havingFirewallService == false) + disallowedActions.push("firewall"); + if (havingPortForwardingService == false) + disallowedActions.push("portForwarding"); + if (havingLbService == false) + disallowedActions.push("loadBalancing"); + + if (args.context.ipAddresses[0].isstaticnat) { //1. Once StaticNat is enabled, hide VPN/PortForwarding/LoadBalancer. + disallowedActions.push("portForwarding"); + disallowedActions.push("loadBalancing"); + } + if (havingVpnService && args.context.ipAddresses[0].vpnenabled) { //2. If VPN service is supported (i.e. IP comes from Guest Network section, not from VPC section), once VPN is enabled, hide StaticNat/PortForwarding/LoadBalancer. + disallowedActions.push("portForwarding"); + disallowedActions.push("loadBalancing"); + } + + //3. Once a PortForwarding rule is added, hide StaticNat/VPN/LoadBalancer. + $.ajax({ + url: createURL('listPortForwardingRules'), + data: { + ipaddressid: args.context.ipAddresses[0].id, + listAll: true + }, + dataType: 'json', + async: false, + success: function(json) { + // Get instance + var rules = json.listportforwardingrulesresponse.portforwardingrule; + if (rules != null && rules.length > 0) { + disallowedActions.push("loadBalancing"); + } + } + }); + + //4. Once a LoadBalancer rule is added, hide StaticNat/VPN/PortForwarding. + $.ajax({ + url: createURL('listLoadBalancerRules'), + data: { + publicipid: args.context.ipAddresses[0].id, + listAll: true + }, + dataType: 'json', + async: false, + success: function(json) { + var rules = json.listloadbalancerrulesresponse.loadbalancerrule; + if (rules != null && rules.length > 0) { + disallowedActions.push("portForwarding"); + } + } + }); + } + } + } + }); + } + } + + return disallowedActions; + }, + + // Firewall rules + firewall: { + noSelect: true, + fields: { + 'cidrlist': { + edit: true, + label: 'label.cidr.list' + }, + 'protocol': { + label: 'label.protocol', + select: function(args) { + args.$select.change(function() { + var $inputs = args.$form.find('input'); + var $icmpFields = $inputs.filter(function() { + var name = $(this).attr('name'); + + return $.inArray(name, [ + 'icmptype', + 'icmpcode' + ]) > -1; + }); + var $otherFields = $inputs.filter(function() { + var name = $(this).attr('name'); + + return name != 'icmptype' && name != 'icmpcode' && name != 'cidrlist'; + }); + + if ($(this).val() == 'icmp') { + $icmpFields.show(); + $icmpFields.attr('disabled', false); + $otherFields.attr('disabled', 'disabled'); + $otherFields.hide(); + $otherFields.parent().find('label.error').hide(); + } else { + $otherFields.show(); + $otherFields.parent().find('label.error').hide(); + $otherFields.attr('disabled', false); + $icmpFields.attr('disabled', 'disabled'); + $icmpFields.hide(); + $icmpFields.parent().find('label.error').hide(); + } + }); + + args.response.success({ + data: [{ + name: 'tcp', + description: 'TCP' + }, { + name: 'udp', + description: 'UDP' + }, { + name: 'icmp', + description: 'ICMP' + }] + }); + } + }, + 'startport': { + edit: true, + label: 'label.start.port', + isOptional: true + }, + 'endport': { + edit: true, + label: 'label.end.port', + isOptional: true + }, + 'icmptype': { + edit: true, + label: 'ICMP.type', + isDisabled: true + }, + 'icmpcode': { + edit: true, + label: 'ICMP.code', + isDisabled: true + }, + 'add-rule': { + label: 'label.add.rule', + addButton: true + }, + 'state' : { + edit: 'ignore', + label: 'label.state' + } + }, + + tags: cloudStack.api.tags({ + resourceType: 'FirewallRule', + contextId: 'multiRule' + }), + + add: { + label: 'label.add', + action: function(args) { + $.ajax({ + url: createURL('createFirewallRule'), + data: $.extend(args.data, { + ipaddressid: args.context.ipAddresses[0].id + }), + dataType: 'json', + success: function(data) { + args.response.success({ + _custom: { + jobId: data.createfirewallruleresponse.jobid + }, + notification: { + label: 'label.add.firewall', + poll: pollAsyncJobResult + } + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }, + actions: { + destroy: { + label: 'label.action.delete.firewall', + action: function(args) { + $.ajax({ + url: createURL('deleteFirewallRule'), + data: { + id: args.context.multiRule[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + var jobID = data.deletefirewallruleresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobID + }, + notification: { + label: 'label.action.delete.firewall', + poll: pollAsyncJobResult + } + }); + }, + + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + } + }, + dataProvider: function(args) { + $.ajax({ + url: createURL('listFirewallRules'), + data: { + listAll: true, + ipaddressid: args.context.ipAddresses[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + args.response.success({ + data: data.listfirewallrulesresponse.firewallrule + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }, + + staticNATDataProvider: function(args) { + $.ajax({ + url: createURL('listPublicIpAddresses'), + data: { + id: args.context.ipAddresses[0].id, + listAll: true + }, + dataType: 'json', + async: true, + success: function(data) { + var ipObj = data.listpublicipaddressesresponse.publicipaddress[0]; + getExtaPropertiesForIpObj(ipObj, args); + + args.response.success({ + data: ipObj + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + vmDataProvider: function(args) { + $.ajax({ + url: createURL('listVirtualMachines'), + data: { + id: args.context.ipAddresses[0].virtualmachineid, + listAll: true + }, + dataType: 'json', + async: true, + success: function(data) { + args.response.success({ + data: data.listvirtualmachinesresponse.virtualmachine[0] + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + vmDetails: cloudStack.sections.instances.listView.detailView, + + // Load balancing rules + loadBalancing: { + listView: $.extend(true, {}, cloudStack.sections.instances, { + listView: { + fields: { + name: { + label: 'label.name' + }, + displayname: { + label: 'label.display.name' + }, + zonename: { + label: 'label.zone.name' + }, + state: { + label: 'label.state', + indicator: { + 'Running': 'on', + 'Stopped': 'off', + 'Destroyed': 'off', + 'Error': 'off' + } + } + }, + filters: false, + + //when server-side change of adding new parameter "vmidipmap" to assignToLoadBalancerRule API is in, uncomment the following commented 4 lines. + subselect: { + isMultiple: true, + label: 'label.use.vm.ips', + dataProvider: multipleVmSecondaryIPSubselect + }, + + dataProvider: function(args) { + var itemData = $.isArray(args.context.multiRule) && args.context.subItemData ? args.context.subItemData : []; + + var data = {}; + listViewDataProvider(args, data); + + var networkid; + if ('vpc' in args.context) { + networkid = args.context.multiData.tier; + } else { + networkid = args.context.ipAddresses[0].associatednetworkid; + } + $.extend(data, { + networkid: networkid + }); + + if (!args.context.projects) { + $.extend(data, { + account: args.context.ipAddresses[0].account, + domainid: args.context.ipAddresses[0].domainid + }); + } + + $.ajax({ + url: createURL('listVirtualMachines'), + data: data, + dataType: 'json', + async: true, + success: function(data) { + var vmData = $.grep( + data.listvirtualmachinesresponse.virtualmachine ? + data.listvirtualmachinesresponse.virtualmachine : [], + function(instance) { + //Hiding the autoScale VMs + var nonAutoScale = 0; + if (instance.displayname == null) + nonAutoScale = 1 + else { + if (instance.displayname.match(/AutoScale-LB-/) == null) + nonAutoScale = 1; + else { + if (instance.displayname.match(/AutoScale-LB-/).length) + nonAutoScale = 0; + } + } + var isActiveState = $.inArray(instance.state, ['Destroyed', 'Expunging']) == -1; + var notExisting = !$.grep(itemData, function(item) { + return item.id == instance.id; + }).length; + + // Check if there are any remaining IPs + if (!notExisting) { + $.ajax({ + url: createURL('listNics'), + async: false, + data: { + virtualmachineid: instance.id + }, + success: function(json) { + var nics = json.listnicsresponse.nic; + + $(nics).map(function (index, nic) { + if (nic.secondaryip) { + var targetIPs = $(nic.secondaryip).map(function (index, sip) { + return sip.ipaddress; + }); + + var lbIPs = $(itemData).map(function(index, item) { return item.itemIp; }); + + targetIPs.push(nic.ipaddress); + + var matchingIPs = $.grep(targetIPs, function(item) { + return $.inArray(item, lbIPs) > -1; + }); + + if (targetIPs.length - matchingIPs.length) { + notExisting = true; + + return false; + } + } + }); + } + }) + } + + return nonAutoScale && isActiveState && notExisting; + } + ); + + args.response.success({ + data: vmData + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + } + }), + headerFields: { + tier: { + label: 'label.tier', + select: function(args) { + if ('vpc' in args.context) { + var data = { + //listAll: true, //do not pass listAll to listNetworks under VPC + domainid: args.context.vpc[0].domainid, + account: args.context.vpc[0].account, + supportedservices: 'Lb' + }; + if (args.context.ipAddresses[0].associatednetworkid == null) { + $.extend(data, { + vpcid: args.context.vpc[0].id, + domainid: args.context.vpc[0].domainid, + account: args.context.vpc[0].account + }); + } else { + $.extend(data, { + id: args.context.ipAddresses[0].associatednetworkid + }); + } + + $.ajax({ + url: createURL("listNetworks"), + data: data, + success: function(json) { + var networks = json.listnetworksresponse.network; + var items = []; + $(networks).each(function() { + items.push({ + id: this.id, + description: this.displaytext + }); + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + multipleAdd: true, + + fields: { + 'name': { + edit: true, + label: 'label.name', + isEditable: true + }, + 'publicport': { + edit: true, + label: 'label.public.port' + }, + 'privateport': { + edit: true, + label: 'label.private.port' + }, + 'algorithm': { + label: 'label.algorithm', + isEditable: true, + select: function(args) { + var data = [{ + id: 'roundrobin', + name: 'roundrobin', + description: _l('label.lb.algorithm.roundrobin') + }, { + id: 'leastconn', + name: 'leastconn', + description: _l('label.lb.algorithm.leastconn') + }, { + id: 'source', + name: 'source', + description: _l('label.lb.algorithm.source') + }]; + if (typeof args.context != 'undefined') { + var lbAlgs = getLBAlgorithms(args.context.networks[0]); + data = (lbAlgs.length == 0) ? data : lbAlgs; + } + args.response.success({ + data: data + }); + } + }, + + 'sticky': { + label: 'label.stickiness', + custom: { + buttonLabel: 'label.configure', + action: cloudStack.lbStickyPolicy.dialog() + } + }, + + 'protocol': { + label: 'label.protocol', + isEditable: true, + select: function(args) { + var data = [{ + id: 'tcp', + name: 'tcp', + description: _l('label.lb.protocol.tcp') + }, { + id: 'udp', + name: 'udp', + description: _l('label.lb.protocol.udp') + }, { + id: 'tcp-proxy', + name: 'tcp-proxy', + description: _l('label.lb.protocol.tcp.proxy') + }, { + id: 'ssl', + name: 'ssl', + description: _l('label.lb.protocol.ssl') + }]; + if (typeof args.context != 'undefined') { + var lbProtocols = getLBProtocols(args.context.networks[0]); + data = (lbProtocols.length == 0) ? data : lbProtocols; + } + args.response.success({ + data: data + }); + } + }, + + 'sslcertificate': { + label: 'label.update.ssl', + custom: { + buttonLabel: 'label.configure', + action: cloudStack.lbCertificatePolicy.dialog() + } + }, + + 'health-check': { + label: 'label.health.check', + custom: { + requireValidation: true, + buttonLabel: 'Configure', + action: cloudStack.uiCustom.healthCheck() + }, + isHidden: function(args) { + if (!('vpc' in args.context)) { //From Guest Network section + var lbProviderIsNetscaler = false; + $.ajax({ + url: createURL('listNetworkOfferings'), + data: { + id: args.context.networks[0].networkofferingid + }, + async: false, + success: function(json) { + var networkOffering = json.listnetworkofferingsresponse.networkoffering[0]; + var services = networkOffering.service; + lbProviderIsNetscaler = checkIfNetScalerProviderIsEnabled(services); + } + }); + if (lbProviderIsNetscaler == true) { //Health-Check is only supported on Netscaler (but not on any other provider) + return false; //Show Health-Check button + } else { + return 2; //Hide Health-Check button (Both Header and Form) + } + } else { //From VPC section + var lbProviderIsNetscaler; + var services = args.context.vpc[0].service; + lbProviderIsNetscaler = checkIfNetScalerProviderIsEnabled(services); + if (lbProviderIsNetscaler == true) { //Health-Check is only supported on Netscaler (but not on any other provider) + return false; //Show Health-Check button + } else { + return 2; //Hide Health-Check button (both Header and Form) + } + } + } + }, + + 'autoScale': { + label: 'label.autoscale', + custom: { + requireValidation: true, + buttonLabel: 'label.configure', + action: cloudStack.uiCustom.autoscaler(cloudStack.autoscaler) + }, + isHidden: function(args) { + if (!('vpc' in args.context)) { //from Guest Network section + var lbProviderIsNetscaler = false; + $.ajax({ + url: createURL('listNetworkOfferings'), + data: { + id: args.context.networks[0].networkofferingid + }, + async: false, + success: function(json) { + var networkOffering = json.listnetworkofferingsresponse.networkoffering[0]; + var services = networkOffering.service; + lbProviderIsNetscaler = checkIfNetScalerProviderIsEnabled(services); + } + }); + if (lbProviderIsNetscaler == true) { //AutoScale is only supported on Netscaler (but not on any other provider like VirtualRouter) + return false; //show AutoScale button + } else { + return 2; //hide Autoscale button (both header and form) + } + } else { //from VPC section + var lbProviderIsNetscaler; + var services = args.context.vpc[0].service; + + lbProviderIsNetscaler = checkIfNetScalerProviderIsEnabled(services); + + if (lbProviderIsNetscaler == true) { //AutoScale is only supported on Netscaler (but not on any other provider like VirtualRouter) + return false; //show AutoScale button + } else { + return 2; //hide Autoscale button (both header and form) + } + } + } + }, + 'add-vm': { + label: 'label.add.vms', + addButton: true + }, + 'state' : { + edit: 'ignore', + label: 'label.state' + } + }, + + tags: cloudStack.api.tags({ + resourceType: 'LoadBalancer', + contextId: 'multiRule' + }), + + add: { + label: 'label.add.vms', + action: function(args) { + var networkid; + if ('vpc' in args.context) { //from VPC section + if (args.data.tier == null) { + args.response.error('Tier is required'); + return; + } + networkid = args.data.tier; + } else if ('networks' in args.context) { //from Guest Network section + networkid = args.context.networks[0].id; + } + var data = { + algorithm: args.data.algorithm, + name: args.data.name, + privateport: args.data.privateport, + publicport: args.data.publicport, + openfirewall: false, + networkid: networkid, + publicipid: args.context.ipAddresses[0].id, + protocol: args.data.protocol + }; + + var stickyData = $.extend(true, {}, args.data.sticky); + var certificateData = $.extend(true, {}, args.data.sslcertificate); + + //***** create new LB rule > Add VMs ***** + $.ajax({ + url: createURL('createLoadBalancerRule'), + data: data, + dataType: 'json', + async: true, + success: function(data) { + var itemData = args.itemData; + var jobID = data.createloadbalancerruleresponse.jobid; + var lbID = data.createloadbalancerruleresponse.id; + + var inputData = { + id: data.createloadbalancerruleresponse.id + }; + + var selectedVMs = args.itemData; + if (selectedVMs != null) { + var vmidipmapIndex = 0; + for (var vmIndex = 0; vmIndex < selectedVMs.length; vmIndex++) { + var selectedIPs = selectedVMs[vmIndex]._subselect; + for (var ipIndex = 0; ipIndex < selectedIPs.length; ipIndex++) { + inputData['vmidipmap[' + vmidipmapIndex + '].vmid'] = selectedVMs[vmIndex].id; + + if (args.context.ipAddresses[0].isportable) { + inputData['vmidipmap[' + vmidipmapIndex + '].vmip'] = selectedIPs[ipIndex].split(',')[1]; + } else { + inputData['vmidipmap[' + vmidipmapIndex + '].vmip'] = selectedIPs[ipIndex]; + } + + vmidipmapIndex++; + } + } + } + + $.ajax({ + url: createURL('assignToLoadBalancerRule'), + data: inputData, + success: function(data) { + var jobID = data.assigntoloadbalancerruleresponse.jobid; + var lbStickyCreated = false; + var lbCertificateCreated = false; + + args.response.success({ + _custom: { + jobId: jobID + }, + notification: { + label: 'label.add.load.balancer', + poll: function(args) { + var complete = args.complete; + var error = args.error; + + pollAsyncJobResult({ + _custom: { + jobId: jobID + }, + complete: function(args) { + if (lbStickyCreated && lbCertificateCreated) { + return; + } + + if (!lbStickyCreated) { + lbStickyCreated = true; + + if (stickyData && stickyData.methodname && stickyData.methodname != 'None') { + cloudStack.lbStickyPolicy.actions.add(lbID, stickyData, complete, error); + } + } + + if (!lbCertificateCreated) { + lbCertificateCreated = true; + + if (certificateData && certificateData.certificate && certificateData.certificate != 'None') { + cloudStack.lbCertificatePolicy.actions.add(lbID, certificateData, complete, error); + } else { + complete(); + } + } else { + complete(); + } + }, + error: error + }); + } + } + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }, + actions: { + edit: { + label: 'label.edit', + action: function(args) { + $.ajax({ + url: createURL('updateLoadBalancerRule'), + data: $.extend(args.data, { + id: args.context.multiRule[0].id + }), + success: function(json) { + args.response.success({ + _custom: { + jobId: json.updateloadbalancerruleresponse.jobid + }, + notification: { + label: 'label.edit.lb.rule', + poll: pollAsyncJobResult + } + }); + } + }); + } + }, + destroy: { + label: 'label.action.delete.load.balancer', + action: function(args) { + $.ajax({ + url: createURL('deleteLoadBalancerRule'), + data: { + id: args.context.multiRule[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + var jobID = data.deleteloadbalancerruleresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobID + }, + notification: { + label: 'label.action.delete.load.balancer', + poll: pollAsyncJobResult + } + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + } + }, + + itemActions: { + //***** update existing LB rule > Add VMs ***** + add: { + label: 'label.add.vms.to.lb', + action: function(args) { + var inputData = { + id: args.multiRule.id + }; + + /* + * e.g. first VM(xxx) has two IPs(10.1.1.~), second VM(yyy) has three IPs(10.2.2.~): + * vmidipmap[0].vmid=xxx vmidipmap[0].vmip=10.1.1.11 + * vmidipmap[1].vmid=xxx vmidipmap[1].vmip=10.1.1.12 + * vmidipmap[2].vmid=yyy vmidipmap[2].vmip=10.2.2.77 + * vmidipmap[3].vmid=yyy vmidipmap[3].vmip=10.2.2.78 + * vmidipmap[4].vmid=yyy vmidipmap[4].vmip=10.2.2.79 + */ + var selectedVMs = args.data; + if (selectedVMs != null) { + var vmidipmapIndex = 0; + for (var vmIndex = 0; vmIndex < selectedVMs.length; vmIndex++) { + var selectedIPs = selectedVMs[vmIndex]._subselect; + for (var ipIndex = 0; ipIndex < selectedIPs.length; ipIndex++) { + inputData['vmidipmap[' + vmidipmapIndex + '].vmid'] = selectedVMs[vmIndex].id; + + if (args.context.ipAddresses[0].isportable) { + inputData['vmidipmap[' + vmidipmapIndex + '].vmip'] = selectedIPs[ipIndex].split(',')[1]; + } else { + inputData['vmidipmap[' + vmidipmapIndex + '].vmip'] = selectedIPs[ipIndex]; + } + + vmidipmapIndex++; + } + } + } + + $.ajax({ + url: createURL('assignToLoadBalancerRule'), + data: inputData, + success: function(json) { + args.response.success({ + notification: { + _custom: { + jobId: json.assigntoloadbalancerruleresponse.jobid + }, + desc: 'label.add.vms.to.lb', + poll: pollAsyncJobResult + } + }); + }, + error: function(json) { + args.response.error(); + cloudStack.dialog.notice({ + message: parseXMLHttpResponse(json) + }); + } + }); + } + }, + destroy: { + label: 'label.remove.vm.from.lb', + action: function(args) { + var inputData; + if (args.item.itemIp == undefined) { + inputData = { + id: args.multiRule.id, + virtualmachineids: args.item.id + }; + } else { + inputData = { + id: args.multiRule.id, + "vmidipmap[0].vmid": args.item.id, + "vmidipmap[0].vmip": args.item.itemIp + }; + } + + $.ajax({ + url: createURL('removeFromLoadBalancerRule'), + data: inputData, + success: function(json) { + args.response.success({ + notification: { + _custom: { + jobId: json.removefromloadbalancerruleresponse.jobid + }, + desc: 'label.remove.vm.from.lb', + poll: pollAsyncJobResult + } + }); + }, + error: function(json) { + args.response.error(); + cloudStack.dialog.notice({ + message: parseXMLHttpResponse(json) + }); + } + }); + } + } + }, + dataProvider: function(args) { + var $multi = args.$multi; + + $.ajax({ + url: createURL('listLoadBalancerRules'), + data: { + publicipid: args.context.ipAddresses[0].id, + listAll: true + }, + dataType: 'json', + async: true, + success: function(data) { + var loadbalancerrules = data.listloadbalancerrulesresponse.loadbalancerrule; + + $(loadbalancerrules).each(function() { + var lbRule = this; + var stickyData = {}; + var sslCertData = {}; + //var lbInstances = []; + var itemData = []; + + // Passing _hideFields array will disable specified fields for this row + //lbRule._hideFields = ['autoScale']; + + $.ajax({ + url: createURL('listAutoScaleVmGroups'), + data: { + listAll: true, + lbruleid: lbRule.id + }, + async: false, + success: function(json) { + if (json.listautoscalevmgroupsresponse.autoscalevmgroup != null && json.listautoscalevmgroupsresponse.autoscalevmgroup.length > 0) { //from 'autoScale' button + lbRule._hideFields = ['add-vm']; + } else { //from 'add-vm' button + lbRule._hideFields = ['autoScale']; + } + } + }); + + // Get sticky data + $.ajax({ + url: createURL('listLBStickinessPolicies'), + async: false, + data: { + listAll: true, + lbruleid: lbRule.id + }, + success: function(json) { + var stickyPolicy = json.listlbstickinesspoliciesresponse.stickinesspolicies ? + json.listlbstickinesspoliciesresponse.stickinesspolicies[0].stickinesspolicy : null; + + if (stickyPolicy && stickyPolicy.length) { + stickyPolicy = stickyPolicy[0]; + + if (!stickyPolicy.methodname) stickyPolicy.methodname = 'None'; + + stickyData = { + _buttonLabel: stickyPolicy.methodname, + methodname: stickyPolicy.methodname, + stickyName: stickyPolicy.name, + id: stickyPolicy.id, + lbRuleID: lbRule.id + }; + $.extend(stickyData, stickyPolicy.params); + } else { + stickyData = { + lbRuleID: lbRule.id + }; + } + }, + error: function(json) { + cloudStack.dialog.notice({ + message: parseXMLHttpResponse(json) + }); + } + }); + + // Get SSL Certificate data + $.ajax({ + url: createURL('listSslCerts'), + data: { + listAll: true, + lbruleid: lbRule.id + }, + async: false, + success: function(json) { + if (json.listsslcertsresponse != null) { + lbRule._hideFields.push('sslcertificate'); + } + } + }); + + // Get instances + $.ajax({ + url: createURL('listLoadBalancerRuleInstances'), + dataType: 'json', + async: false, + data: { + listAll: true, + lbvmips: true, + id: lbRule.id + }, + success: function(data) { + //when "lbvmips: true" is not passed to API + //lbVMs = data.listloadbalancerruleinstancesresponse.loadbalancerruleinstance; + + //when "lbvmips: true" is passed to API + lbrulevmidips = data.listloadbalancerruleinstancesresponse.lbrulevmidip; + + if (lbrulevmidips != null) { + for (var k = 0; k < lbrulevmidips.length; k++) { + var lbrulevmidip = lbrulevmidips[k]; + var lbVM = lbrulevmidip.loadbalancerruleinstance; + if (lbVM.displayname.indexOf('AutoScale-LB-') > -1) //autoscale VM is not allowed to be deleted manually. So, hide destroy button + lbVM._hideActions = ['destroy']; + + if (lbVM.servicestate) { + lbVM._itemStateLabel = 'label.service.state'; + lbVM._itemState = lbVM.servicestate; + } + + if (lbrulevmidip.lbvmipaddresses != null) { + for (var m = 0 ; m < lbrulevmidip.lbvmipaddresses.length; m++) { + var ip = lbrulevmidip.lbvmipaddresses[m]; + itemData.push($.extend({}, lbVM, { + itemIp: ip + })); + } + } else { + itemData.push(lbVM); + } + } + } + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + + $.extend(lbRule, { + _itemName: 'name', + _itemIp: 'itemIp', + _itemData: itemData, + _maxLength: { + name: 7 + }, + sticky: stickyData, + autoScale: { + lbRuleID: lbRule.id + } + }); + }); + + args.response.success({ + data: loadbalancerrules + }); + } + }); + + // Check if tiers are present; hide/show header drop-down (begin) *** + //dataProvider() is called when a LB rule is added in multiEdit. However, adding a LB rule might change parent object (IP Address object). So, we have to force to refresh args.context.ipAddresses[0] here + $.ajax({ + url: createURL('listPublicIpAddresses'), + data: { + id: args.context.ipAddresses[0].id, + listAll: true + }, + success: function(json) { + var ipObj = json.listpublicipaddressesresponse.publicipaddress[0]; + getExtaPropertiesForIpObj(ipObj, args); + + args.context.ipAddresses.shift(); //remove the first element in args.context.ipAddresses + args.context.ipAddresses.push(ipObj); + + var $headerFields = $multi.find('.header-fields'); + if ('vpc' in args.context) { + if (args.context.ipAddresses[0].associatednetworkid == null) { + $headerFields.show(); + } else { + $headerFields.hide(); + } + } else if ('networks' in args.context) { + $headerFields.hide(); + } + } + }); + // Check if tiers are present; hide/show header drop-down (end) *** + } + }, + + // Port forwarding rules + portForwarding: { + headerFields: { + tier: { + label: 'label.tier', + select: function(args) { + if ('vpc' in args.context) { + var data = { + //listAll: true, //do not pass listAll to listNetworks under VPC + domainid: args.context.vpc[0].domainid, + account: args.context.vpc[0].account, + supportedservices: 'PortForwarding' + }; + if (args.context.ipAddresses[0].associatednetworkid == null) { + $.extend(data, { + vpcid: args.context.vpc[0].id, + domainid: args.context.vpc[0].domainid, + account: args.context.vpc[0].account + }); + } else { + $.extend(data, { + id: args.context.ipAddresses[0].associatednetworkid + }); + } + $.ajax({ + url: createURL("listNetworks"), + data: data, + success: function(json) { + var networks = json.listnetworksresponse.network; + var items = []; + $(networks).each(function() { + items.push({ + id: this.id, + description: this.displaytext + }); + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + listView: $.extend(true, {}, cloudStack.sections.instances, { + listView: { + filters: false, + subselect: { + label: 'label.use.vm.ip', + dataProvider: singleVmSecondaryIPSubselect + }, + dataProvider: function(args) { + var data = {}; + listViewDataProvider(args, data); + + var networkid; + if ('vpc' in args.context) { + networkid = args.context.multiData.tier; + } else { + networkid = args.context.ipAddresses[0].associatednetworkid; + } + $.extend(data, { + networkid: networkid + }); + + if (!args.context.projects) { + $.extend(data, { + account: args.context.ipAddresses[0].account, + domainid: args.context.ipAddresses[0].domainid + }); + } + + $.ajax({ + url: createURL('listVirtualMachines'), + data: data, + dataType: 'json', + async: true, + success: function(data) { + args.response.success({ + data: $.grep( + data.listvirtualmachinesresponse.virtualmachine ? + data.listvirtualmachinesresponse.virtualmachine : [], + function(instance) { + return $.inArray(instance.state, [ + 'Destroyed', 'Expunging' + ]) == -1; + } + ) + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + } + }), + fields: { + //'private-ports': { + privateport: { + edit: true, + label: 'label.private.port', + //range: ['privateport', 'privateendport'] //Bug 13427 - Don't allow port forwarding ranges in the CreatePortForwardingRule API + range: ['privateport', 'privateendport'] //Bug 16344 (restore port range back) (http://bugs.cloudstack.org/browse/CS-16344) + }, + //'public-ports': { + publicport: { + edit: true, + label: 'label.public.port', + //range: ['publicport', 'publicendport'] //Bug 13427 - Don't allow port forwarding ranges in the CreatePortForwardingRule API + range: ['publicport', 'publicendport'] //Bug 16344 (restore port range back) (http://bugs.cloudstack.org/browse/CS-16344) + }, + 'protocol': { + label: 'label.protocol', + select: function(args) { + args.response.success({ + data: [{ + name: 'tcp', + description: 'TCP' + }, { + name: 'udp', + description: 'UDP' + }] + }); + } + }, + 'state' : { + edit: 'ignore', + label: 'label.state' + }, + 'add-vm': { + label: 'label.add.vm', + addButton: true + } + }, + + tags: cloudStack.api.tags({ + resourceType: 'PortForwardingRule', + contextId: 'multiRule' + }), + + add: { + label: 'label.add.vm', + + action: function(args) { + var data = { + ipaddressid: args.context.ipAddresses[0].id, + privateport: args.data.privateport, + privateendport: args.data.privateendport, + publicport: args.data.publicport, + publicendport: args.data.publicendport, + protocol: args.data.protocol, + virtualmachineid: args.itemData[0].id, + openfirewall: false + }; + + if (args.context.ipAddresses[0].isportable) { + var subselect = args.itemData[0]._subselect.split(','); + //var networkid = subselect[0]; + var vmguestip = subselect[1]; + + //data.networkid = networkid; + + if (parseInt(vmguestip) !== -1) { + data.vmguestip = vmguestip; + } + } else if (args.itemData[0]._subselect && args.itemData[0]._subselect != -1) { + data.vmguestip = args.itemData[0]._subselect; + } + + if ('vpc' in args.context) { //from VPC section + if (args.data.tier == null) { + args.response.error('Tier is required'); + return; + } + $.extend(data, { + networkid: args.data.tier + }); + } else { //from Guest Network section + $.extend(data, { + networkid: args.context.networks[0].id + }); + } + + $.ajax({ + url: createURL('createPortForwardingRule'), + data: data, + success: function(data) { + args.response.success({ + _custom: { + jobId: data.createportforwardingruleresponse.jobid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.portforwardingrule; + } + }, + notification: { + label: 'label.add.port.forwarding.rule', + poll: pollAsyncJobResult + } + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }, + actions: { + destroy: { + label: 'label.remove.pf', + action: function(args) { + $.ajax({ + url: createURL('deletePortForwardingRule'), + data: { + id: args.context.multiRule[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + var jobID = data.deleteportforwardingruleresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobID + }, + notification: { + label: 'label.remove.pf', + poll: pollAsyncJobResult + } + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + } + }, + dataProvider: function(args) { + var $multi = args.$multi; + + $.ajax({ + url: createURL('listPortForwardingRules'), + data: { + ipaddressid: args.context.ipAddresses[0].id, + listAll: true + }, + dataType: 'json', + async: true, + success: function(data) { + // Get instance + var portForwardingData = data + .listportforwardingrulesresponse.portforwardingrule; + var loadTotal = portForwardingData ? portForwardingData.length : 0; + var loadCurrent = 0; + + $(portForwardingData).each(function() { + var item = this; + + item._itemName = '_displayName'; + + $.ajax({ + url: createURL('listVirtualMachines'), + dataType: 'json', + async: true, + data: { + listAll: true, + id: item.virtualmachineid + }, + success: function(data) { + loadCurrent++; + var vms = data.listvirtualmachinesresponse.virtualmachine; + + //if this VM is destroyed, data.listvirtualmachinesresponse.virtualmachine will be undefined for regular-user (CLOUDSTACK-3195) + if (vms == undefined) { + vms = [{ + "id": item.virtualmachineid, + "name": item.virtualmachinename, + "displayname": item.virtualmachinedisplayname + }]; + } + + $.extend(item, { + _itemData: $.map(vms, function(vm) { + return $.extend(vm, { + _displayName: '

VM: ' + vm.name + '

' + '

IP: ' + item.vmguestip + '

' // Also display attached IP + }); + }), + _context: { + instances: vms + } + }); + + if (loadCurrent == loadTotal) { + args.response.success({ + data: portForwardingData + }); + } + } + }); + }); + + // Check if tiers are present; hide/show header drop-down (begin) *** + //dataProvider() is called when a PF rule is added in multiEdit. However, adding a LB rule might change parent object (IP Address object). So, we have to force to refresh args.context.ipAddresses[0] here + $.ajax({ + url: createURL('listPublicIpAddresses'), + data: { + id: args.context.ipAddresses[0].id, + listAll: true + }, + success: function(json) { + var ipObj = json.listpublicipaddressesresponse.publicipaddress[0]; + getExtaPropertiesForIpObj(ipObj, args); + + args.context.ipAddresses.shift(); //remove the first element in args.context.ipAddresses + args.context.ipAddresses.push(ipObj); + + var $headerFields = $multi.find('.header-fields'); + if ('vpc' in args.context) { + if (args.context.ipAddresses[0].associatednetworkid == null) { + $headerFields.show(); + } else { + $headerFields.hide(); + } + } else if ('networks' in args.context) { + $headerFields.hide(); + } + } + }); + // Check if tiers are present; hide/show header drop-down (end) *** + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + } + }) + }, + vpn: { + title: 'label.vpn', + custom: function(args) { + var ipAddress = args.context.ipAddresses[0].ipaddress; + var psk = ""; + if (args.context.ipAddresses[0].remoteaccessvpn != null) + psk = args.context.ipAddresses[0].remoteaccessvpn.presharedkey; + + return $('
') + .append( + $('
    ').addClass('info') + .append( + // VPN IP + $('
  • ').addClass('ip').html(_l('message.enabled.vpn') + ' ') + .append($('').html(ipAddress)) + ) + .append( + // PSK + $('
  • ').addClass('psk').html(_l('message.enabled.vpn.ip.sec') + ' ') + .append($('').html(psk)) + ) + .append( + //Note + $('
  • ').html(_l('message.enabled.vpn.note')) + ) + ) + } + } + } + } + } + }, + securityGroups: { + type: 'select', + title: 'label.menu.security.groups', + id: 'securityGroups', + listView: { + id: 'securityGroups', + label: 'label.menu.security.groups', + fields: { + name: { + label: 'label.name', + editable: true + }, + description: { + label: 'label.description' + }, + domain: { + label: 'label.domain' + }, + account: { + label: 'label.account' + } + }, + actions: { + add: { + label: 'label.add.security.group', + + action: function(args) { + $.ajax({ + url: createURL('createSecurityGroup'), + data: { + name: args.data.name, + description: args.data.description + }, + success: function(data) { + args.response.success({ + data: data.createsecuritygroupresponse.securitygroup + }); + }, + + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + notification: { + poll: function(args) { + args.complete({ + actionFilter: actionFilters.securityGroups + }); + } + }, + + messages: { + confirm: function(args) { + return _l('message.question.are.you.sure.you.want.to.add') + ' ' + args.name + '?'; + }, + notification: function(args) { + return 'label.add.security.group'; + } + }, + + createForm: { + title: 'label.add.security.group', + desc: 'label.add.security.group', + fields: { + name: { + label: 'label.name' + }, + description: { + label: 'label.description' + } + } + } + } + }, + + advSearchFields: { + tagKey: { + label: 'label.tag.key' + }, + tagValue: { + label: 'label.tag.value' + } + }, + + dataProvider: function(args) { + var data = {}; + listViewDataProvider(args, data); + + if (args.context != null) { + if ("securityGroups" in args.context) { + $.extend(data, { + id: args.context.securityGroups[0].id + }); + } + } + + $.ajax({ + url: createURL('listSecurityGroups'), + data: data, + success: function(json) { + var items = json.listsecuritygroupsresponse.securitygroup; + args.response.success({ + actionFilter: actionFilters.securityGroups, + data: items + }); + } + }); + }, + + detailView: { + name: 'Security group details', + tabs: { + details: { + title: 'label.details', + fields: [{ + name: { + label: 'label.name', + isEditable: true, + validation: { + required: true + } + } + }, { + id: { + label: 'label.id' + }, + description: { + label: 'label.description' + }, + domain: { + label: 'label.domain' + }, + account: { + label: 'label.account' + } + }], + + tags: cloudStack.api.tags({ + resourceType: 'SecurityGroup', + contextId: 'securityGroups' + }), + + + dataProvider: function(args) { + $.ajax({ + url: createURL("listSecurityGroups&id=" + args.id), + dataType: "json", + async: true, + success: function(json) { + var items = json.listsecuritygroupsresponse.securitygroup; + if (items != null && items.length > 0) { + args.response.success({ + actionFilter: actionFilters.securityGroups, + data: items[0] + }); + } + } + }); + } + }, + ingressRules: { + title: 'label.ingress.rule', + custom: cloudStack.uiCustom.securityRules({ + noSelect: true, + noHeaderActionsColumn: true, + fields: { + 'protocol': { + label: 'label.protocol', + select: function(args) { + args.$select.change(function() { + var $inputs = args.$form.find('th, td'); + var $icmpFields = $inputs.filter(function() { + var name = $(this).attr('rel'); + + return $.inArray(name, [ + 'icmptype', + 'icmpcode' + ]) > -1; + }); + var $otherFields = $inputs.filter(function() { + var name = $(this).attr('rel'); + + return name != 'protocolnumber' && + name != 'icmptype' && + name != 'icmpcode' && + name != 'protocol' && + name != 'add-rule' && + name != 'cidr' && + name != 'accountname' && + name != 'securitygroup'; + }); + + $portFields = $inputs.filter(function() { + var name = $(this).attr('rel'); + return $.inArray(name, [ + 'startport', + 'endport' + ]) > -1; + }); + $protocolFields = $inputs.filter(function() { + var name = $(this).attr('rel'); + + return $.inArray(name, ['protocolnumber']) > -1; + }); + + if ($(this).val() == 'protocolnumber') { + $icmpFields.hide(); + $portFields.hide(); + $protocolFields.show(); + } else if ($(this).val() == 'icmp') { + $icmpFields.show(); + $protocolFields.hide(); + $portFields.hide(); + } else if ($(this).val() == 'all') { + $portFields.hide(); + $icmpFields.hide(); + $protocolFields.hide(); + } else { + $otherFields.show(); + $icmpFields.hide(); + $protocolFields.hide(); + } + }); + + args.response.success({ + data: [{ + name: 'tcp', + description: 'TCP' + }, { + name: 'udp', + description: 'UDP' + }, { + name: 'icmp', + description: 'ICMP' + }, { + name: 'all', + description: 'ALL' + }, { + name: 'protocolnumber', + description: 'Protocol Number' + }] + }); + } + }, + 'protocolnumber': { + label: 'label.protocol.number', + edit: true, + isHidden: true, + isEditable: true + }, + 'startport': { + edit: true, + label: 'label.start.port', + validation: { + number: true, + range: [0, 65535] + } + }, + 'endport': { + edit: true, + label: 'label.end.port', + validation: { + number: true, + range: [0, 65535] + } + }, + 'icmptype': { + edit: true, + label: 'ICMP.type', + isHidden: true + }, + 'icmpcode': { + edit: true, + label: 'ICMP.code', + isHidden: true + }, + 'cidr': { + edit: true, + label: 'label.cidr', + isHidden: true, + validation: { + ipv46cidrs: true + } + }, + 'accountname': { + edit: true, + label: 'label.account.and.security.group', + isHidden: true, + range: ['accountname', 'securitygroup'] + }, + 'add-rule': { + label: 'label.add', + addButton: true + } + }, + add: { + label: 'label.add', + action: function(args) { + var data = { + securitygroupid: args.context.securityGroups[0].id, + domainid: args.context.securityGroups[0].domainid, + account: args.context.securityGroups[0].account + }; + + if (args.data.protocol == 'protocolnumber') { + $.extend(data, { + protocol: args.data.protocolnumber + }); + } else { + $.extend(data, { + protocol: args.data.protocol + }); + } + + if (args.data.icmptype && args.data.icmpcode) { // ICMP + $.extend(data, { + icmptype: args.data.icmptype, + icmpcode: args.data.icmpcode + }); + } else { // TCP/UDP + $.extend(data, { + startport: args.data.startport, + endport: args.data.endport + }); + } + + // CIDR / account + if (args.data.cidr) { + data.cidrlist = args.data.cidr; + } else { + data['usersecuritygrouplist[0].account'] = args.data.accountname; + data['usersecuritygrouplist[0].group'] = args.data.securitygroup; + } + + $.ajax({ + url: createURL('authorizeSecurityGroupIngress'), + data: data, + dataType: 'json', + async: true, + success: function(data) { + var jobId = data.authorizesecuritygroupingressresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobId + }, + notification: { + label: 'label.add.ingress.rule', + poll: pollAsyncJobResult + } + }); + } + }); + } + }, + actions: { + destroy: { + label: 'label.remove.rule', + action: function(args) { + $.ajax({ + url: createURL('revokeSecurityGroupIngress'), + data: { + domainid: args.context.securityGroups[0].domainid, + account: args.context.securityGroups[0].account, + id: args.context.multiRule[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + var jobID = data.revokesecuritygroupingressresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobID + }, + notification: { + label: 'label.remove.ingress.rule', + poll: pollAsyncJobResult + } + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + }, + ignoreEmptyFields: true, + tags: cloudStack.api.tags({ + resourceType: 'SecurityGroupRule', + contextId: 'multiRule' + }), + dataProvider: function(args) { + $.ajax({ + url: createURL('listSecurityGroups'), + data: { + id: args.context.securityGroups[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + args.response.success({ + data: $.map( + data.listsecuritygroupsresponse.securitygroup[0].ingressrule ? + data.listsecuritygroupsresponse.securitygroup[0].ingressrule : [], + ingressEgressDataMap + ) + }); + } + }); + } + }) + }, + + egressRules: { + title: 'label.egress.rule', + custom: cloudStack.uiCustom.securityRules({ + noSelect: true, + noHeaderActionsColumn: true, + fields: { + 'protocol': { + label: 'label.protocol', + select: function(args) { + args.$select.change(function() { + var $inputs = args.$form.find('th, td'); + var $icmpFields = $inputs.filter(function() { + var name = $(this).attr('rel'); + + return $.inArray(name, [ + 'icmptype', + 'icmpcode' + ]) > -1; + }); + var $otherFields = $inputs.filter(function() { + var name = $(this).attr('rel'); + + return name != 'protocolnumber' && + name != 'icmptype' && + name != 'icmpcode' && + name != 'protocol' && + name != 'add-rule' && + name != 'cidr' && + name != 'accountname' && + name != 'securitygroup'; + }); + + $portFields = $inputs.filter(function() { + var name = $(this).attr('rel'); + return $.inArray(name, [ + 'startport', + 'endport' + ]) > -1; + }); + $protocolFields = $inputs.filter(function() { + var name = $(this).attr('rel'); + + return $.inArray(name, ['protocolnumber']) > -1; + }); + + if ($(this).val() == 'protocolnumber') { + $icmpFields.hide(); + $portFields.hide(); + $protocolFields.show(); + } else if ($(this).val() == 'icmp') { + $icmpFields.show(); + $protocolFields.hide(); + $portFields.hide(); + } else if ($(this).val() == 'all') { + $portFields.hide(); + $icmpFields.hide(); + $protocolFields.hide(); + } else { + $otherFields.show(); + $icmpFields.hide(); + $protocolFields.hide(); + } + }); + + args.response.success({ + data: [{ + name: 'tcp', + description: 'TCP' + }, { + name: 'udp', + description: 'UDP' + }, { + name: 'icmp', + description: 'ICMP' + }, { + name: 'all', + description: 'ALL' + }, { + name: 'protocolnumber', + description: 'Protocol Number' + }] + }); + } + }, + 'protocolnumber': { + label: 'label.protocol.number', + edit: true, + isHidden: true, + isEditable: true + }, + 'startport': { + edit: true, + label: 'label.start.port', + validation: { + number: true, + range: [0, 65535] + } + }, + 'endport': { + edit: true, + label: 'label.end.port', + validation: { + number: true, + range: [0, 65535] + } + }, + 'icmptype': { + edit: true, + label: 'ICMP.type', + isHidden: true + }, + 'icmpcode': { + edit: true, + label: 'ICMP.code', + isHidden: true + }, + 'cidr': { + edit: true, + label: 'label.cidr', + isHidden: true, + validation: { + ipv46cidrs: true + } + }, + 'accountname': { + edit: true, + label: 'label.account.and.security.group', + isHidden: true, + range: ['accountname', 'securitygroup'] + }, + 'add-rule': { + label: 'label.add', + addButton: true + } + }, + add: { + label: 'label.add', + action: function(args) { + var data = { + securitygroupid: args.context.securityGroups[0].id, + domainid: args.context.securityGroups[0].domainid, + account: args.context.securityGroups[0].account + }; + + if (args.data.protocol == 'protocolnumber') { + $.extend(data, { + protocol: args.data.protocolnumber + }); + } else { + $.extend(data, { + protocol: args.data.protocol + }); + } + + if (args.data.icmptype && args.data.icmpcode) { // ICMP + $.extend(data, { + icmptype: args.data.icmptype, + icmpcode: args.data.icmpcode + }); + } else { // TCP/UDP + $.extend(data, { + startport: args.data.startport, + endport: args.data.endport + }); + } + + // CIDR / account + if (args.data.cidr) { + data.cidrlist = args.data.cidr; + } else { + data['usersecuritygrouplist[0].account'] = args.data.accountname; + data['usersecuritygrouplist[0].group'] = args.data.securitygroup; + } + + $.ajax({ + url: createURL('authorizeSecurityGroupEgress'), + data: data, + dataType: 'json', + async: true, + success: function(data) { + var jobId = data.authorizesecuritygroupegressresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobId + }, + notification: { + label: 'label.add.egress.rule', + poll: pollAsyncJobResult + } + }); + } + }); + } + }, + actions: { + destroy: { + label: 'label.remove.rule', + action: function(args) { + $.ajax({ + url: createURL('revokeSecurityGroupEgress'), + data: { + domainid: args.context.securityGroups[0].domainid, + account: args.context.securityGroups[0].account, + id: args.context.multiRule[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + var jobID = data.revokesecuritygroupegressresponse.jobid; + + args.response.success({ + _custom: { + jobId: jobID + }, + notification: { + label: 'label.remove.egress.rule', + poll: pollAsyncJobResult + } + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + }, + ignoreEmptyFields: true, + tags: cloudStack.api.tags({ + resourceType: 'SecurityGroupRule', + contextId: 'multiRule' + }), + dataProvider: function(args) { + $.ajax({ + url: createURL('listSecurityGroups'), + data: { + id: args.context.securityGroups[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + args.response.success({ + data: $.map( + data.listsecuritygroupsresponse.securitygroup[0].egressrule ? + data.listsecuritygroupsresponse.securitygroup[0].egressrule : [], + ingressEgressDataMap + ) + }); + } + }); + } + }) + } + }, + + actions: { + edit: { + label: 'label.edit', + action: function(args) { + var data = { + id: args.context.securityGroups[0].id + }; + if (args.data.name != args.context.securityGroups[0].name) { + $.extend(data, { + name: args.data.name + }); + }; + $.ajax({ + url: createURL('updateSecurityGroup'), + data: data, + success: function(json) { + var item = json.updatesecuritygroupresponse.securitygroup; + args.response.success({ + data: item + }); + } + }); + } + }, + + remove: { + label: 'label.action.delete.security.group', + messages: { + confirm: function(args) { + return 'message.action.delete.security.group'; + }, + notification: function(args) { + return 'label.action.delete.security.group'; + } + }, + action: function(args) { + $.ajax({ + url: createURL('deleteSecurityGroup'), + data: { + id: args.context.securityGroups[0].id + }, + dataType: 'json', + async: true, + success: function(data) { + args.response.success(); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + + notification: { + poll: function(args) { + args.complete({ + data: { + state: 'Destroyed' + }, + actionFilter: actionFilters.securityGroups + }); + } + } + } + } + } + } + }, + vpc: { + type: 'select', + title: 'label.vpc', + id: 'vpc', + listView: { + id: 'vpc', + label: 'label.vpc', + fields: { + name: { + label: 'label.name' + }, + displaytext: { + label: 'label.description', + truncate: true + }, + zonename: { + label: 'label.zone', + truncate: true + }, + cidr: { + label: 'label.cidr' + }, + state: { + label: 'label.state', + indicator: { + 'Enabled': 'on', + 'Disabled': 'off' + } + } + }, + + advSearchFields: { + name: { + label: 'label.name' + }, + zoneid: { + label: 'label.zone', + select: function(args) { + $.ajax({ + url: createURL('listZones'), + data: { + listAll: true + }, + success: function(json) { + var zones = json.listzonesresponse.zone ? json.listzonesresponse.zone : []; + + args.response.success({ + data: $.map(zones, function(zone) { + return { + id: zone.id, + description: zone.name + }; + }) + }); + } + }); + } + }, + + domainid: { + label: 'label.domain', + select: function(args) { + if (isAdmin() || isDomainAdmin()) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + success: function(json) { + var array1 = [{ + id: '', + description: '' + }]; + var domains = json.listdomainsresponse.domain; + if (domains != null && domains.length > 0) { + for (var i = 0; i < domains.length; i++) { + array1.push({ + id: domains[i].id, + description: domains[i].path + }); + } + } + array1.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: array1 + }); + } + }); + } else { + args.response.success({ + data: null + }); + } + }, + isHidden: function(args) { + if (isAdmin() || isDomainAdmin()) + return false; + else + return true; + } + }, + + account: { + label: 'label.account', + isHidden: function(args) { + if (isAdmin() || isDomainAdmin()) + return false; + else + return true; + } + }, + tagKey: { + label: 'label.tag.key' + }, + tagValue: { + label: 'label.tag.value' + } + }, + + dataProvider: function(args) { + var data = {}; + listViewDataProvider(args, data); + + $.ajax({ + url: createURL('listVPCs'), + data: data, + success: function(json) { + var items = json.listvpcsresponse.vpc ? json.listvpcsresponse.vpc : { }; + + //If we are coming from Home > Regions, show only regional vpcs + if (args.context.regions) + items = $.grep( + items, + function (vpc, i) { + return vpc.regionlevelvpc; + }); + + args.response.success({ + data: items + }); + }, + error: function(XMLHttpResponse) { + cloudStack.dialog.notice({ + message: parseXMLHttpResponse(XMLHttpResponse) + }); + args.response.error(); + } + }); + }, + actions: { + add: { + label: 'label.add.vpc', + messages: { + notification: function(args) { + return 'label.add.vpc'; + } + }, + createForm: { + title: 'label.add.vpc', + messages: { + notification: function(args) { + return 'label.add.vpc'; + } + }, + fields: { + name: { + label: 'label.name', + docID: 'helpVPCName', + validation: { + required: true + } + }, + displaytext: { + label: 'label.description', + docID: 'helpVPCDescription', + validation: { + required: true + } + }, + zoneid: { + label: 'label.zone', + docID: 'helpVPCZone', + validation: { + required: true + }, + select: function(args) { + var data = {}; + $.ajax({ + url: createURL('listZones'), + data: data, + success: function(json) { + var zones = json.listzonesresponse.zone ? json.listzonesresponse.zone : []; + var advZones = $.grep(zones, function(zone) { + return zone.networktype == 'Advanced' && !zone.securitygroupsenabled; + }); + + args.response.success({ + data: $.map(advZones, function(zone) { + return { + id: zone.id, + description: zone.name + }; + }) + }); + } + }); + } + }, + cidr: { + label: 'label.super.cidr.for.guest.networks', + docID: 'helpVPCSuperCIDR', + validation: { + required: true, + ipv4cidr: true + } + }, + networkdomain: { + docID: 'helpVPCDomain', + label: 'label.DNS.domain.for.guest.networks' + //format: FQDN + }, + vpcoffering: { + label: 'label.vpc.offering', + dependsOn: 'zoneid', + validation: { + required: true + }, + select: function(args) { + var data = { + zoneid: args.zoneid + }; + $.ajax({ + url: createURL('listVPCOfferings'), + data: data, + success: function(json) { + var offerings = json.listvpcofferingsresponse.vpcoffering ? json.listvpcofferingsresponse.vpcoffering : []; + var filteredofferings = $.grep(offerings, function(offering) { + return offering.state == 'Enabled'; + }); + args.response.success({ + data: $.map(filteredofferings, function(vpco) { + return { + id: vpco.id, + description: vpco.name + }; + }) + }); + } + }); + } + } + } + }, + action: function(args) { + var vpcOfferingName = args.data.vpcoffering; + var dataObj = { + name: args.data.name, + displaytext: args.data.displaytext, + zoneid: args.data.zoneid, + cidr: args.data.cidr, + vpcofferingid: args.data.vpcoffering + }; + + if (args.data.networkdomain != null && args.data.networkdomain.length > 0) + $.extend(dataObj, { + networkdomain: args.data.networkdomain + }); + + $.ajax({ + url: createURL("createVPC"), + dataType: "json", + data: dataObj, + async: true, + success: function(vpcjson) { + var jid = vpcjson.createvpcresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.vpc; + } + } + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + + }, + configureVpc: { + label: 'label.configure.vpc', + textLabel: 'label.configure', + action: { + custom: cloudStack.uiCustom.vpc(cloudStack.vpc) + } + } + }, + + detailView: { + name: 'label.details', + actions: { + configureVpc: { + label: 'label.configure', + textLabel: 'label.configure', + action: { + custom: cloudStack.uiCustom.vpc(cloudStack.vpc) + }, + messages: { + notification: function() { + return ''; + } + } + }, + + edit: { + label: 'label.edit', + action: function(args) { + $.ajax({ + url: createURL('updateVPC'), + data: { + id: args.context.vpc[0].id, + name: args.data.name, + displaytext: args.data.displaytext + }, + success: function(json) { + var jid = json.updatevpcresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.vpc; + } + } + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + restart: { + label: 'label.restart.vpc', + createForm: { + title: 'label.restart.vpc', + desc: function(args) { + if (Boolean(args.context.vpc[0].redundantvpcrouter)) { + return 'message.restart.vpc'; + } else { + return 'message.restart.vpc.remark'; + } + }, + + preFilter: function(args) { + var zoneObj; + $.ajax({ + url: createURL("listZones&id=" + args.context.vpc[0].zoneid), + dataType: "json", + async: false, + success: function(json) { + zoneObj = json.listzonesresponse.zone[0]; + } + }); + + + args.$form.find('.form-item[rel=cleanup]').find('input').attr('checked', 'checked'); //checked + args.$form.find('.form-item[rel=cleanup]').css('display', 'inline-block'); //shown + args.$form.find('.form-item[rel=makeredundant]').find('input').attr('checked', 'checked'); //checked + args.$form.find('.form-item[rel=makeredundant]').css('display', 'inline-block'); //shown + + if (Boolean(args.context.vpc[0].redundantvpcrouter)) { + args.$form.find('.form-item[rel=makeredundant]').hide(); + } else { + args.$form.find('.form-item[rel=makeredundant]').show(); + } + }, + fields: { + cleanup: { + label: 'label.clean.up', + isBoolean: true + }, + makeredundant: { + label: 'label.make.redundant', + isBoolean: true + } + } + }, + messages: { + confirm: function(args) { + return 'message.restart.vpc'; + }, + notification: function(args) { + return 'label.restart.vpc'; + } + }, + + action: function(args) { + $.ajax({ + url: createURL("restartVPC"), + data: { + id: args.context.vpc[0].id, + cleanup: (args.data.cleanup == "on"), + makeredundant: (args.data.makeredundant == "on") + }, + success: function(json) { + var jid = json.restartvpcresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.vpc; + } + } + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + remove: { + label: 'label.remove.vpc', + messages: { + confirm: function(args) { + return 'message.remove.vpc'; + }, + notification: function(args) { + return 'label.remove.vpc'; + } + }, + action: function(args) { + $.ajax({ + url: createURL("deleteVPC"), + data: { + id: args.context.vpc[0].id + }, + success: function(json) { + var jid = json.deletevpcresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + }, + error: function(data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + + tabFilter: function(args) { + var hiddenTabs = []; + var isRouterOwner = isAdmin(); + if (!isRouterOwner) { + hiddenTabs.push("router"); + hiddenTabs.push("virtualRouters"); + } + return hiddenTabs; + }, + + tabs: { + details: { + title: 'label.details', + fields: [{ + name: { + label: 'label.name', + isEditable: true + } + }, { + displaytext: { + label: 'label.description', + isEditable: true + }, + account: { + label: 'label.account' + }, + domain: { + label: 'label.domain' + }, + zonename: { + label: 'label.zone' + }, + cidr: { + label: 'label.cidr' + }, + networkdomain: { + label: 'label.network.domain' + }, + state: { + label: 'label.state' + }, + ispersistent: { + label: 'label.persistent', + converter: function(booleanValue) { + if (booleanValue == true) { + return "Yes"; + } + + return "No"; + } + }, + redundantvpcrouter: { + label: 'label.redundant.vpc', + converter: function(booleanValue) { + if (booleanValue == true) { + return "Yes"; + } + + return "No"; + } + }, + restartrequired: { + label: 'label.restart.required', + converter: function(booleanValue) { + if (booleanValue == true) { + return "Yes"; + } + + return "No"; + } + }, + id: { + label: 'label.id' + } + }], + + tags: cloudStack.api.tags({ + resourceType: 'Vpc', + contextId: 'vpc' + }), + + dataProvider: function(args) { + $.ajax({ + url: createURL("listVPCs"), + dataType: "json", + data: { + id: args.context.vpc[0].id + }, + async: true, + success: function(json) { + var item = json.listvpcsresponse.vpc[0]; + args.response.success({ + data: item + }); + } + }); + } + }, + router: { + title: 'label.vpc.router.details', + fields: [{ + name: { + label: 'label.name' + } + }, { + state: { + label: 'label.state' + }, + hostname: { + label: 'label.host' + }, + linklocalip: { + label: 'label.linklocal.ip' + }, + isredundantrouter: { + label: 'label.redundant.router', + converter: function(booleanValue) { + if (booleanValue == true) { + return "Yes"; + } + return "No"; + } + }, + redundantstate: { + label: 'label.redundant.state' + }, + id: { + label: 'label.id' + }, + serviceofferingname: { + label: 'label.service.offering' + }, + zonename: { + label: 'label.zone' + }, + gateway: { + label: 'label.gateway' + }, + publicip: { + label: 'label.public.ip' + }, + guestipaddress: { + label: 'label.guest.ip' + }, + dns1: { + label: 'label.dns' + }, + account: { + label: 'label.account' + }, + domain: { + label: 'label.domain' + } + }], + + dataProvider: function(args) { + $.ajax({ + url: createURL("listRouters&listAll=true&vpcid=" + args.context.vpc[0].id), + dataType: "json", + async: true, + success: function(json) { + for (var i = 0; i < json.listroutersresponse.router.length; i++) { + var item = json.listroutersresponse.router[i]; + + args.response.success({ + actionFilter: cloudStack.sections.system.routerActionFilter, + data: item + }); + } + } + }); + } + }, + virtualRouters: { + title: "label.virtual.routers", + listView: cloudStack.sections.system.subsections.virtualRouters.sections.routerNoGroup.listView + } + } + } + } + }, + + vpnCustomerGateway: { + type: 'select', + title: 'label.vpn.customer.gateway', + listView: { + id: 'vpnCustomerGateway', + label: 'label.vpn.customer.gateway', + fields: { + name: { + label: 'label.name' + }, + gateway: { + label: 'label.gateway' + }, + cidrlist: { + label: 'label.CIDR.list' + }, + ipsecpsk: { + label: 'label.IPsec.preshared.key' + } + }, + + advSearchFields: { + keyword: { + label: 'label.name' + }, + domainid: { + label: 'label.domain', + select: function(args) { + if (isAdmin() || isDomainAdmin()) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + success: function(json) { + var array1 = [{ + id: '', + description: '' + }]; + var domains = json.listdomainsresponse.domain; + if (domains != null && domains.length > 0) { + for (var i = 0; i < domains.length; i++) { + array1.push({ + id: domains[i].id, + description: domains[i].path + }); + } + } + array1.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: array1 + }); + } + }); + } else { + args.response.success({ + data: null + }); + } + }, + isHidden: function(args) { + if (isAdmin() || isDomainAdmin()) + return false; + else + return true; + } + }, + account: { + label: 'Account', + isHidden: function(args) { + if (isAdmin() || isDomainAdmin()) + return false; + else + return true; + } + } + }, + + dataProvider: function(args) { + var data = {}; + listViewDataProvider(args, data); + + $.ajax({ + url: createURL('listVpnCustomerGateways'), + data: data, + async: true, + success: function(json) { + var items = json.listvpncustomergatewaysresponse.vpncustomergateway; + args.response.success({ + data: items + }); + } + }); + }, + + actions: { + add: { + label: 'label.add.vpn.customer.gateway', + messages: { + notification: function(args) { + return 'label.add.vpn.customer.gateway'; + } + }, + createForm: { + title: 'label.add.vpn.customer.gateway', + fields: { + name: { + label: 'label.name', + docID: 'helpVPNGatewayName', + validation: { + required: true + } + }, + gateway: { + label: 'label.gateway', + validation: { + required: true + } + }, + cidrlist: { + label: 'label.CIDR.list', + desc: 'message.enter.seperated.list.multiple.cidrs', + validation: { + required: true + } + }, + gateway: { + label: 'label.gateway', + docID: 'helpVPNGatewayGateway', + validation: { + required: true + } + }, + cidrlist: { + label: 'label.CIDR.list', + desc: 'message.enter.seperated.list.multiple.cidrs', + docID: 'helpVPNGatewayCIDRList', + validation: { + required: true + } + }, + ipsecpsk: { + label: 'label.IPsec.preshared.key', + docID: 'helpVPNGatewayIPsecPresharedKey', + validation: { + required: true + } + }, + + //IKE Policy + ikeEncryption: { + label: 'label.IKE.encryption', + docID: 'helpVPNGatewayIKEEncryption', + select: function(args) { + var items = []; + items.push({ + id: 'aes128', + description: 'aes128' + }); + items.push({ + id: 'aes192', + description: 'aes192' + }); + items.push({ + id: 'aes256', + description: 'aes256' + }); + items.push({ + id: '3des', + description: '3des' + }); + args.response.success({ + data: items + }); + } + }, + ikeHash: { + label: 'label.IKE.hash', + docID: 'helpVPNGatewayIKEHash', + select: function(args) { + var items = []; + items.push({ + id: 'sha1', + description: 'sha1' + }); + items.push({ + id: 'sha256', + description: 'sha256' + }); + items.push({ + id: 'sha384', + description: 'sha384' + }); + items.push({ + id: 'sha512', + description: 'sha512' + }); + items.push({ + id: 'md5', + description: 'md5' + }); + args.response.success({ + data: items + }); + } + }, + ikeDh: { + label: 'label.IKE.DH', + docID: 'helpVPNGatewayIKEDH', + select: function(args) { + var items = []; + items.push({ + id: 'modp1536', + description: 'Group 5(modp1536)' + }); + items.push({ + id: 'modp2048', + description: 'Group 14(modp2048)' + }); + items.push({ + id: 'modp3072', + description: 'Group 15(modp3072)' + }); + items.push({ + id: 'modp4096', + description: 'Group 16(modp4096)' + }); + items.push({ + id: 'modp6144', + description: 'Group 17(modp6144)' + }); + items.push({ + id: 'modp8192', + description: 'Group 18(modp8192)' + }); + items.push({ + id: 'modp1024', + description: 'Group 2(modp1024)' + }); + args.response.success({ + data: items + }); + } + }, + + //ESP Policy + espEncryption: { + label: 'label.ESP.encryption', + docID: 'helpVPNGatewayESPLifetime', + select: function(args) { + var items = []; + items.push({ + id: 'aes128', + description: 'aes128' + }); + items.push({ + id: 'aes192', + description: 'aes192' + }); + items.push({ + id: 'aes256', + description: 'aes256' + }); + items.push({ + id: '3des', + description: '3des' + }); + args.response.success({ + data: items + }); + } + }, + espHash: { + label: 'label.ESP.hash', + docID: 'helpVPNGatewayESPHash', + select: function(args) { + var items = []; + items.push({ + id: 'sha1', + description: 'sha1' + }); + items.push({ + id: 'sha256', + description: 'sha256' + }); + items.push({ + id: 'sha384', + description: 'sha384' + }); + items.push({ + id: 'sha512', + description: 'sha512' + }); + items.push({ + id: 'md5', + description: 'md5' + }); + args.response.success({ + data: items + }); + } + }, + perfectForwardSecrecy: { + label: 'label.perfect.forward.secrecy', + docID: 'helpVPNGatewayPerfectForwardSecrecy', + select: function(args) { + var items = []; + items.push({ + id: '', + description: _l('label.none') + }); + items.push({ + id: 'modp1536', + description: 'Group 5(modp1536)' + }); + items.push({ + id: 'modp2048', + description: 'Group 14(modp2048)' + }); + items.push({ + id: 'modp3072', + description: 'Group 15(modp3072)' + }); + items.push({ + id: 'modp4096', + description: 'Group 16(modp4096)' + }); + items.push({ + id: 'modp6144', + description: 'Group 17(modp6144)' + }); + items.push({ + id: 'modp8192', + description: 'Group 18(modp8192)' + }); + items.push({ + id: 'modp1024', + description: 'Group 2(modp1024)' + }); + args.response.success({ + data: items + }); + } + }, + + ikelifetime: { + label: 'label.IKE.lifetime', + docID: 'helpVPNGatewayIKELifetime', + defaultValue: '86400', + validation: { + required: false, + number: true + } + }, + esplifetime: { + label: 'label.ESP.lifetime', + docID: 'helpVPNGatewayESPLifetime', + defaultValue: '3600', + validation: { + required: false, + number: true + } + }, + + dpd: { + label: 'label.dead.peer.detection', + docID: 'helpVPNGatewayDeadPeerDetection', + isBoolean: true, + isChecked: false + }, + + forceencap: { + label: 'label.vpn.force.encapsulation', + docID: 'helpVPNGatewayForceEncapsulation', + docID: 'helpVPNGatewayForceEncapsulation', + isBoolean: true, + isChecked: false + } + } + }, + action: function(args) { + var data = { + name: args.data.name, + gateway: args.data.gateway, + cidrlist: args.data.cidrlist, + ipsecpsk: args.data.ipsecpsk, + ikelifetime: args.data.ikelifetime, + esplifetime: args.data.esplifetime, + dpd: (args.data.dpd == "on"), + forceencap: (args.data.forceencap == "on") + }; + + var ikepolicy = args.data.ikeEncryption + '-' + args.data.ikeHash; + if (args.data.ikeDh != null && args.data.ikeDh.length > 0) + ikepolicy += ';' + args.data.ikeDh; + + $.extend(data, { + ikepolicy: ikepolicy + }); + + var esppolicy = args.data.espEncryption + '-' + args.data.espHash; + if (args.data.perfectForwardSecrecy != null && args.data.perfectForwardSecrecy.length > 0) + esppolicy += ';' + args.data.perfectForwardSecrecy; + + $.extend(data, { + esppolicy: esppolicy + }); + + $.ajax({ + url: createURL('createVpnCustomerGateway'), + data: data, + dataType: 'json', + success: function(json) { + var jid = json.createvpncustomergatewayresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.vpncustomergateway; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + + detailView: { + name: 'label.details', + actions: { + edit: { + label: 'label.edit', + action: function(args) { + var data = { + id: args.context.vpnCustomerGateway[0].id, + name: args.data.name, + gateway: args.data.gateway, + cidrlist: args.data.cidrlist, + ipsecpsk: args.data.ipsecpsk, + ikelifetime: args.data.ikelifetime, + esplifetime: args.data.esplifetime, + dpd: (args.data.dpd == "on"), + forceencap: (args.data.forceencap == "on") + }; + + var ikepolicy = args.data.ikeEncryption + '-' + args.data.ikeHash; + if (args.data.ikeDh != null && args.data.ikeDh.length > 0) + ikepolicy += ';' + args.data.ikeDh; + + $.extend(data, { + ikepolicy: ikepolicy + }); + + var esppolicy = args.data.espEncryption + '-' + args.data.espHash; + if (args.data.perfectForwardSecrecy != null && args.data.perfectForwardSecrecy.length > 0) + esppolicy += ';' + args.data.perfectForwardSecrecy; + + $.extend(data, { + esppolicy: esppolicy + }); + + $.ajax({ + url: createURL('updateVpnCustomerGateway'), + data: data, + success: function(json) { + var jobId = json.updatevpncustomergatewayresponse.jobid; + args.response.success({ + _custom: { + jobId: jobId, + getUpdatedItem: function(json) { + var item = json.queryasyncjobresultresponse.jobresult.vpncustomergateway; + args.response.success({ + data: item + }); + } + } + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + remove: { + label: 'label.delete.VPN.customer.gateway', + messages: { + confirm: function(args) { + return 'message.delete.VPN.customer.gateway'; + }, + notification: function(args) { + return 'label.delete.VPN.customer.gateway'; + } + }, + action: function(args) { + $.ajax({ + url: createURL("deleteVpnCustomerGateway"), + data: { + id: args.context.vpnCustomerGateway[0].id + }, + success: function(json) { + var jid = json.deletevpncustomergatewayresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + + tabs: { + details: { + title: 'label.details', + fields: [{ + name: { + label: 'label.name', + isEditable: true, + validation: { + required: true + } + } + }, { + gateway: { + label: 'label.gateway', + isEditable: true, + validation: { + required: true + } + }, + cidrlist: { + label: 'label.CIDR.list', + isEditable: true, + validation: { + required: true + } + }, + ipsecpsk: { + label: 'label.IPsec.preshared.key', + isEditable: true, + validation: { + required: true + } + }, + + //IKE Policy + ikeEncryption: { + label: 'label.IKE.encryption', + isEditable: true, + select: function(args) { + var items = []; + items.push({ + id: '3des', + description: '3des' + }); + items.push({ + id: 'aes128', + description: 'aes128' + }); + items.push({ + id: 'aes192', + description: 'aes192' + }); + items.push({ + id: 'aes256', + description: 'aes256' + }); + args.response.success({ + data: items + }); + } + }, + ikeHash: { + label: 'label.IKE.hash', + isEditable: true, + select: function(args) { + var items = []; + items.push({ + id: 'md5', + description: 'md5' + }); + items.push({ + id: 'sha1', + description: 'sha1' + }); + args.response.success({ + data: items + }); + } + }, + ikeDh: { + label: 'label.IKE.DH', + isEditable: true, + select: function(args) { + var items = []; + items.push({ + id: '', + description: _l('label.none') + }); + items.push({ + id: 'modp1024', + description: 'Group 2(modp1024)' + }); + items.push({ + id: 'modp1536', + description: 'Group 5(modp1536)' + }); + args.response.success({ + data: items + }); + } + }, + + //ESP Policy + espEncryption: { + label: 'label.ESP.encryption', + isEditable: true, + select: function(args) { + var items = []; + items.push({ + id: '3des', + description: '3des' + }); + items.push({ + id: 'aes128', + description: 'aes128' + }); + items.push({ + id: 'aes192', + description: 'aes192' + }); + items.push({ + id: 'aes256', + description: 'aes256' + }); + args.response.success({ + data: items + }); + } + }, + espHash: { + label: 'label.ESP.hash', + isEditable: true, + select: function(args) { + var items = []; + items.push({ + id: 'md5', + description: 'md5' + }); + items.push({ + id: 'sha1', + description: 'sha1' + }); + args.response.success({ + data: items + }); + } + }, + perfectForwardSecrecy: { + label: 'label.perfect.forward.secrecy', + isEditable: true, + select: function(args) { + var items = []; + items.push({ + id: '', + description: _l('label.none') + }); + items.push({ + id: 'modp1024', + description: 'Group 2(modp1024)' + }); + items.push({ + id: 'modp1536', + description: 'Group 5(modp1536)' + }); + args.response.success({ + data: items + }); + } + }, + + ikelifetime: { + label: 'label.IKE.lifetime', + isEditable: true, + validation: { + required: false, + number: true + } + }, + esplifetime: { + label: 'label.ESP.lifetime', + isEditable: true, + validation: { + required: false, + number: true + } + }, + + dpd: { + label: 'label.dead.peer.detection', + isBoolean: true, + isEditable: true, + converter: cloudStack.converters.toBooleanText + }, + + forceencap: { + label: 'label.vpn.force.encapsulation', + isBoolean: true, + isEditable: true, + converter: cloudStack.converters.toBooleanText + }, + + id: { + label: 'label.id' + }, + domain: { + label: 'label.domain' + }, + account: { + label: 'label.account' + } + }], + + dataProvider: function(args) { + $.ajax({ + url: createURL("listVpnCustomerGateways"), + data: { + id: args.context.vpnCustomerGateway[0].id + }, + success: function(json) { + var item = json.listvpncustomergatewaysresponse.vpncustomergateway[0]; + + //IKE Policy + var a1 = item.ikepolicy.split('-'); //e.g. item.ikepolicy == '3des-md5;modp1024' + item.ikeEncryption = a1[0]; + if (a1[1].indexOf(';') == -1) { + item.ikeHash = a1[1]; + } else { + var a2 = a1[1].split(';'); + item.ikeHash = a2[0]; + item.ikeDh = a2[1]; + } + + //ESP Policy + var a1 = item.esppolicy.split('-'); //e.g. item.esppolicy == '3des-md5' or '3des-md5;modp1024' + item.espEncryption = a1[0]; + if (a1[1].indexOf(';') == -1) { + item.espHash = a1[1]; + } else { + var a2 = a1[1].split(';'); + item.espHash = a2[0]; + item.perfectForwardSecrecy = a2[1]; + } + + args.response.success({ + data: item + }); + } + }); + } + } + } + } + } + }, + vpnuser: { + type: 'select', + title: 'label.vpn.users', + listView: { + id: 'vpnUsers', + label: 'label.vpn.users', + fields: { + username: { + label: 'label.name' + }, + domain: { + label: 'label.domain' + }, + state: { + label: 'label.state' + } + }, + + dataProvider: function(args) { + var data = {}; + listViewDataProvider(args, data); + + $.ajax({ + url: createURL('listVpnUsers'), + data: data, + dataType: 'json', + success: function(json) { + var items = json.listvpnusersresponse.vpnuser; + args.response.success({ + data: items + }); + } + }); + }, + + actions:{ + destroy: { + label: 'label.action.delete.user', + messages: { + confirm: function(args) { + return 'message.action.delete.vpn.user' + }, + notification: function(args) { + return 'label.delete.vpn.user' + } + }, + action: function(args) { + $.ajax({ + url: createURL('removeVpnUser'), + data: { + domainid: args.context.vpnuser[0].domainid, + account: args.context.vpnuser[0].account, + username: args.context.vpnuser[0].username + }, + dataType: 'json', + async: true, + success: function(json) { + var jobID = json.removevpnuserresponse.jobid; + args.response.success({ + _custom: { + jobId: jobID + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + add: { + label: 'label.add.user', + messages: { + notification: function(args) { + return 'label.add.vpn.user'; + } + }, + createForm:{ + title: 'label.add.vpn.user', + fields: { + username: { + edit: true, + label: 'label.username', + validation: { + required: true + } + }, + password: { + edit: true, + isPassword: true, + label: 'label.password', + validation: { + required: true + } + }, + domain: { + label: 'label.domain', + isHidden: function(args) { + if (isAdmin() || isDomainAdmin()) + return false; + else + return true; + }, + select: function(args) { + if (isAdmin() || isDomainAdmin()) { + $.ajax({ + url: createURL("listDomains&listAll=true"), + success: function(json) { + var items = []; + items.push({ + id: "", + description: "" + }); + var domainObjs = json.listdomainsresponse.domain; + $(domainObjs).each(function() { + items.push({ + id: this.id, + description: this.path + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + args.response.success({ + data: items + }); + } + }); + args.$select.change(function() { + var $form = $(this).closest('form'); + if ($(this).val() == "") { + $form.find('.form-item[rel=account]').hide(); + } else { + $form.find('.form-item[rel=account]').css('display', 'inline-block'); + } + }); + } else { + args.response.success({ + data: null + }); + } + } + }, + account: { + label: 'label.account', + validation: { + required: true + }, + isHidden: function(args) { + if (isAdmin() || isDomainAdmin()) { + return false; + } else { + return true; + } + } + } + } + }, + action: function(args) { + var data = { + username: args.data.username, + password: args.data.password + }; + + if (args.data.domain != null && args.data.domain.length > 0) { + $.extend(data, { + domainid: args.data.domain + }); + if (args.data.account != null && args.data.account.length > 0) { + $.extend(data, { + account: args.data.account + }); + } + } + + $.ajax({ + url: createURL('addVpnUser'), + data: data, + dataType: 'json', + async: true, + success: function(json) { + var jid = json.addvpnuserresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + return json.queryasyncjobresultresponse.jobresult.vpnuser; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + + detailView: { + name: 'label.details', + actions: { + destroy: { + label: 'label.action.delete.user', + messages: { + confirm: function(args) { + return 'message.action.delete.vpn.user'; + }, + notification: function(args) { + return 'label.delete.vpn.user'; + } + }, + action: function(args) { + $.ajax({ + url: createURL("removeVpnUser"), + data: { + domainid: args.context.vpnuser[0].domainid, + account: args.context.vpnuser[0].account, + username: args.context.vpnuser[0].username + }, + dataType: 'json', + async: true, + success: function(json) { + var jid = json.removevpnuserresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + + tabs: { + details: { + title: 'label.details', + fields: [{ + username: { + label: 'label.name', + validation: { + required: true + } + } + }, { + domain: { + label: 'label.domain' + }, + state: { + label: 'label.state' + }, + }], + + dataProvider: function(args) { + $.ajax({ + url: createURL("listVpnUsers"), + data: { + id: args.context.vpnuser[0].id + }, + success: function(json) { + var item = json.listvpnusersresponse.vpnuser[0]; + + args.response.success({ + data: item + }); + } + }); + } + } + } + } + } + } + } + }; + + function checkIfNetScalerProviderIsEnabled(services) { + if (services != null) { + for (var i = 0; i < services.length; i++) { + if (services[i].name == 'Lb') { + var providers = services[i].provider; + if (providers != null) { + for (var k = 0; k < providers.length; k++) { + if (providers[k].name == 'Netscaler') { + return true; + } + } + } + return false; + } + } + } + + return false; + } + + function getExtaPropertiesForIpObj(ipObj, args) { + if (!('vpc' in args.context)) { //***** Guest Network section > Guest Network page > IP Address page ***** + var services = args.context.networks[0].service; + if(services != null) { + for(var i = 0; i < services.length; i++) { + var thisService = services[i]; + if (thisService.name == "Vpn") { + ipObj.networkOfferingHavingVpnService = true; + break; + } + } + } + if (ipObj.networkOfferingHavingVpnService == true) { + $.ajax({ + url: createURL('listRemoteAccessVpns'), + data: { + listAll: true, + publicipid: ipObj.id + }, + async: false, + success: function(vpnResponse) { + var isVPNEnabled = vpnResponse.listremoteaccessvpnsresponse.count; + if (isVPNEnabled) { + ipObj.vpnenabled = true; + ipObj.remoteaccessvpn = vpnResponse.listremoteaccessvpnsresponse.remoteaccessvpn[0]; + } else { + ipObj.vpnenabled = false; + } + } + }); + } + } else { //***** VPC section > Configuration VPC > Router > Public IP Addresses ***** + if (ipObj.issourcenat) { //VPC sourceNAT IP: supports VPN + $.ajax({ + url: createURL('listRemoteAccessVpns'), + data: { + listAll: true, + publicipid: ipObj.id + }, + async: false, + success: function(vpnResponse) { + var isVPNEnabled = vpnResponse.listremoteaccessvpnsresponse.count; + if (isVPNEnabled) { + ipObj.vpnenabled = true; + ipObj.remoteaccessvpn = vpnResponse.listremoteaccessvpnsresponse.remoteaccessvpn[0]; + } else { + ipObj.vpnenabled = false; + } + } + }); + } + } + }; + + var getLBAlgorithms = function(networkObj) { + if (!networkObj || !networkObj.service) { + return []; + } + + var lbService = $.grep(networkObj.service, function(service) { + return service.name == 'Lb'; + })[0]; + + if (!lbService || !lbService.capability) { + return []; + } + + var algorithmCapabilities = $.grep( + lbService.capability, + function(capability) { + return capability.name == 'SupportedLbAlgorithms'; + } + )[0]; + + if (!algorithmCapabilities) { + return []; + } + + var algorithms = algorithmCapabilities.value.split(','); + + if (!algorithms) { + return []; + } + + var data = []; + $(algorithms).each(function() { + data.push({id: this.valueOf(), name: this.valueOf(), description: _l('label.lb.algorithm.' + this.valueOf())}); + }); + + return data; + } + + function getForcedInfoAndUpdateNetwork(data, args) { + if (isAdmin()) { + cloudStack.dialog.confirm({ + message: "message.confirm.force.update", + action: function() { + $.extend(data, { + forced: true + }); + + $.ajax({ + url: createURL('updateNetwork'), + async: false, + data: data, + success: function(json) { + var jid = json.updatenetworkresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + var item = json.queryasyncjobresultresponse.jobresult.network; + return { + data: item + }; + } + } + }); + } + }); + }, + cancelAction: function() { + $.ajax({ + url: createURL('updateNetwork'), + async: false, + data: data, + success: function(json) { + var jid = json.updatenetworkresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + var item = json.queryasyncjobresultresponse.jobresult.network; + return { + data: item + }; + } + } + }); + } + }); + } + }); + } + else { + $.ajax({ + url: createURL('updateNetwork'), + async: false, + data: data, + success: function(json) { + var jid = json.updatenetworkresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + var item = json.queryasyncjobresultresponse.jobresult.network; + return { + data: item + }; + } + } + }); + } + }); + } + } + + var getLBProtocols = function(networkObj) { + if (!networkObj || !networkObj.service) { + return []; + } + + var lbService = $.grep(networkObj.service, function(service) { + return service.name == 'Lb'; + })[0]; + + if (!lbService || !lbService.capability) { + return []; + } + + var protocolCapabilities = $.grep( + lbService.capability, + function(capability) { + return (capability.name == 'SupportedProtocols'); + } + )[0]; + + if (!protocolCapabilities) { + return []; + } + + // make sure protocols are found in a script compatible way: i.e. "tcp,udp,tcp.proxy" , no minus sign or spaces + var protocols = protocolCapabilities.value.replace(/\s/g,'').replace('-','.').split(','); + + if (!protocols) { + return []; + } + + var data = []; + $(protocols).each(function() { + data.push({id: this.valueOf(), name: this.valueOf(), description: _l('label.lb.protocol.' + this.valueOf())}); + }); + + protocolCapabilities = $.grep( + lbService.capability, + function(capability) { + return (capability.name == 'SslTermination' && (capability.value == 'true' || capability.value == true)); + } + )[0]; + + if (!protocolCapabilities) { + return data; + } + + var protocols = protocolCapabilities.value.split(','); + + if (!protocols) { + return data; + } + + $(protocols).each(function() { + data.push({id: 'ssl', name: 'ssl', description: _l('label.lb.protocol.ssl')}); + }); + + return data; + } + +})(cloudStack, jQuery); diff --git a/ui/scripts/system.js b/ui/scripts/system.js new file mode 100755 index 000000000000..5bd461a4a2be --- /dev/null +++ b/ui/scripts/system.js @@ -0,0 +1,23278 @@ +// 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. + +(function ($, cloudStack) { + + var zoneObjs, podObjs, clusterObjs, domainObjs, networkOfferingObjs, physicalNetworkObjs; + var selectedClusterObj, selectedZoneObj, selectedPublicNetworkObj, selectedManagementNetworkObj, selectedPhysicalNetworkObj, selectedGuestNetworkObj; + var nspMap = { + }; + //from listNetworkServiceProviders API + var nspHardcodingArray =[]; //for service providers listView (hardcoding, not from listNetworkServiceProviders API) + + // Add router type to virtual router + // -- can be either Project, VPC, or System (standard) + var mapRouterType = function (index, router) { + var routerType = _l('label.menu.system'); + + if (router.projectid) { + routerType = _l('label.project'); + router.account = router.project; + } + + if (router.vpcid) { + routerType = _l('label.vpc'); + router.guestnetworkname = router.vpcname; + } + + if (router.isredundantrouter) { + router.guestnetworkname = router.guestnetworkname + " (" + router.redundantstate + ")"; + } + + return $.extend(router, { + routerType: routerType + }); + }; + + cloudStack.publicIpRangeAccount = { + dialog: function (args) { + return function (args) { + var data = args.data ? args.data: { + }; + var fields = { + systemvms: { + label: 'label.system.vms', + isBoolean: true, + docID: 'helpSetReservationSystemVms', + defaultValue: data.systemvms + }, + account: { + label: 'label.account', + defaultValue: data.account + }, + domainid: { + label: 'label.domain', + defaultValue: data.domainid, + select: function (args) { + $.ajax({ + url: createURL('listDomains'), + data: { + details: 'min', + listAll: true + }, + success: function (json) { + args.response.success({ + data: $.map(json.listdomainsresponse.domain, function (domain) { + return { + id: domain.id, + description: domain.path + }; + }) + }); + } + }); + } + } + }; + var success = args.response.success; + + if (args.$item) { + // Account data is read-only after creation + $.ajax({ + url: createURL('listDomains'), + data: { + id: data.domainid, + details: 'min', + listAll: true + }, + success: function (json) { + var domain = json.listdomainsresponse.domain[0]; + + if (data.forSystemVms != null) { + systemvms = '
  • ' + _l('label.system.vms') + ': ' + data.forSystemVms + '
  • ' + } + if (data.account != null) + cloudStack.dialog.notice({ + message: '
    • ' + _l('label.account') + ': ' + data.account + '
    • ' + '
    • ' + _l('label.domain') + ': ' + domain.path + '
    • ' + systemvms + '
    ' + }); + else + cloudStack.dialog.notice({ + message: '
    • ' + _l('label.domain') + ': ' + domain.path + '
    • ' + systemvms + '
    ' + }); + } + }); + } else { + cloudStack.dialog.createForm({ + form: { + title: 'label.set.reservation', + desc: 'label.set.reservation.desc', + fields: fields, + preFilter: function(args) { + var $systemvms = args.$form.find('.form-item[rel=systemvms]'); + var $systemvmsCb = $systemvms.find('input[type=checkbox]'); + var $account = args.$form.find('.form-item[rel=account]'); + var $accountTxt = args.$form.find('input[name=account]'); + var $domainid = args.$form.find('select[name=domainid]'); + $systemvmsCb.change(function() { + if ($systemvmsCb.is(':checked')) { + $accountTxt.val(''); + $accountTxt.attr('disabled', true); + $domainid.attr('disabled', true); + } + else { + $accountTxt.attr('disabled', false); + $domainid.attr('disabled', false); + } + }); + } + }, + after: function (args) { + var data = cloudStack.serializeForm(args.$form); + + success({ + data: data + }); + } + }); + } + }; + } + }; + + var getTrafficType = function (physicalNetwork, typeID) { + var trafficType = { + }; + + $.ajax({ + url: createURL('listTrafficTypes'), + data: { + physicalnetworkid: physicalNetwork.id + }, + async: false, + success: function (json) { + trafficType = $.grep( + json.listtraffictypesresponse.traffictype, + function (trafficType) { + return trafficType.traffictype == typeID; + })[0]; + } + }); + + if (trafficType.xennetworklabel == null || trafficType.xennetworklabel == 0) + trafficType.xennetworklabel = _l( 'label.network.label.display.for.blank.value'); + if (trafficType.kvmnetworklabel == null || trafficType.kvmnetworklabel == 0) + trafficType.kvmnetworklabel = _l( 'label.network.label.display.for.blank.value'); + if (trafficType.vmwarenetworklabel == null || trafficType.vmwarenetworklabel == 0) + trafficType.vmwarenetworklabel = _l( 'label.network.label.display.for.blank.value'); + if (trafficType.ovmnetworklabel == null || trafficType.ovmnetworklabel == 0) + trafficType.ovmnetworklabel = _l( 'label.network.label.display.for.blank.value'); + if (trafficType.lxcnetworklabel == null || trafficType.lxcnetworklabel == 0) + trafficType.lxcnetworklabel = _l( 'label.network.label.display.for.blank.value'); + if (trafficType.hypervnetworklabel == null || trafficType.hypervnetworklabel == 0) + trafficType.hypervnetworklabel = _l( 'label.network.label.display.for.blank.value'); + if (trafficType.ovm3networklabel == null || trafficType.ovm3networklabel == 0) + trafficType.ovm3networklabel = _l( 'label.network.label.display.for.blank.value'); + + return trafficType; + }; + + var updateTrafficLabels = function (trafficType, labels, complete) { + var array1 =[]; + if (labels.xennetworklabel != _l( 'label.network.label.display.for.blank.value')) + array1.push("&xennetworklabel=" + labels.xennetworklabel); + if (labels.kvmnetworklabel != _l( 'label.network.label.display.for.blank.value')) + array1.push("&kvmnetworklabel=" + labels.kvmnetworklabel); + if (labels.vmwarenetworklabel != _l( 'label.network.label.display.for.blank.value')) + array1.push("&vmwarenetworklabel=" + labels.vmwarenetworklabel); + if (labels.ovmnetworklabel != _l( 'label.network.label.display.for.blank.value')) + array1.push("&ovmnetworklabel=" + labels.ovmnetworklabel); + if (labels.lxcnetworklabel != _l( 'label.network.label.display.for.blank.value')) + array1.push("&lxcnetworklabel=" + labels.lxcnetworklabel); + if (labels.hypervnetworklabel != _l( 'label.network.label.display.for.blank.value')) + array1.push("&hypervnetworklabel=" + labels.hypervnetworklabel); + if (labels.ovm3networklabel != _l( 'label.network.label.display.for.blank.value')) + array1.push("&ovm3networklabel=" + labels.ovm3networklabel); + + $.ajax({ + url: createURL('updateTrafficType' + array1.join("")), + data: { + id: trafficType.id + }, + success: function (json) { + var jobID = json.updatetraffictyperesponse.jobid; + + cloudStack.ui.notifications.add({ + desc: 'Update traffic labels', + poll: pollAsyncJobResult, + section: 'System', + _custom: { + jobId: jobID + } + }, + complete ? complete: function () { + }, + { + }, + function (data) { + // Error + cloudStack.dialog.notice({ + message: parseXMLHttpResponse(data) + }); + }, + { + }); + } + }) + }; + + function virtualRouterProviderActionFilter(args) { + var allowedActions =[]; + var jsonObj = args.context.item; //args.context.item == nspMap["virtualRouter"] + if (jsonObj.state == "Enabled") + allowedActions.push("disable"); else if (jsonObj.state == "Disabled") + allowedActions.push("enable"); + return allowedActions; + }; + + function ovsProviderActionFilter(args) { + var allowedActions = []; + var jsonObj = args.context.item; //args.context.item == nspMap["virtualRouter"] + if (jsonObj.state == "Enabled") + allowedActions.push("disable"); + else if (jsonObj.state == "Disabled") + allowedActions.push("enable"); + return allowedActions; + }; + + var rollingMaintenanceAction = function(args) { + var isCluster = args.entity === 'clusters'; + var isZone = args.entity === 'zones'; + var isPod = args.entity === 'pods'; + var isHost = args.entity === 'hosts'; + var action = { + messages: { + notification: function(args) { + return 'label.start.rolling.maintenance'; + } + }, + label: 'label.start.rolling.maintenance', + addRow: 'false', + createForm: { + title: 'label.start.rolling.maintenance', + fields: { + timeout: { + label: 'label.timeout', + }, + force: { + isBoolean: true, + label: 'label.start.rolling.maintenance.force' + }, + payload: { + label: 'label.start.rolling.maintenance.payload' + } + } + }, + action: function(args) { + var selectedIds; + if (isCluster) { + selectedIds = args.context.clusters.map(x => x.id); + } else if (isZone) { + selectedIds = args.context.physicalResources.map(x => x.id); + } else if (isPod) { + selectedIds = args.context.pods.map(x => x.id); + } else if (isHost) { + selectedIds = args.context.hosts.map(x => x.id); + } + var ids = selectedIds.join(','); + var data = { + force: args.data.force, + timeout: args.data.timeout, + payload: args.data.payload + }; + if (isCluster) { + $.extend(data, { + clusterids : ids + }); + } else if (isZone) { + $.extend(data, { + zoneids : ids + }); + } else if (isPod) { + $.extend(data, { + podids : ids + }); + } else if (isHost) { + $.extend(data, { + hostids : ids + }); + } + + $.ajax({ + url: createURL("startRollingMaintenance"), + dataType: "json", + data: data, + async: true, + success: function (json) { + var item = json.startrollingmaintenanceresponse; + var jid = item.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }; + + if (args && args.listView) { + $.extend(action, { + isHeader: true, + isMultiSelectAction: true + }); + } + + return action; + }; + + cloudStack.sections.system = { + title: 'label.menu.infrastructure', + id: 'system', + + // System dashboard + dashboard: { + dataProvider: function (args) { + $.ajax({ + url: createURL('listInfrastructure'), + success: function (json) { + var response = json.listinfrastructureresponse.infrastructure; + var data = {}; + data.zoneCount = response.zones; + data.podCount = response.pods; + data.clusterCount = response.clusters; + data.hostCount = response.hosts; + data.primaryStorageCount = response.storagepools; + data.secondaryStorageCount = response.imagestores; + data.systemVmCount = response.systemvms; + data.virtualRouterCount = response.routers; + data.socketCount = response.cpusockets; + data.managementServerCount = response.managementservers; + args.response.success({ + data: data + }); + } + }); + } + }, + + zoneDashboard: function (args) { + $.ajax({ + url: createURL('listCapacity'), + data: { + zoneid: args.context.zones[0].id + }, + success: function (json) { + var capacities = json.listcapacityresponse.capacity; + var data = { + }; + + $(capacities).each(function () { + var capacity = this; + + data[capacity.type] = { + used: cloudStack.converters.convertByType(capacity.type, capacity.capacityused), + total: cloudStack.converters.convertByType(capacity.type, capacity.capacitytotal), + percent: parseInt(capacity.percentused) + }; + }); + + args.response.success({ + data: data + }); + } + }); + }, + + // Network-as-a-service configuration + naas: { + providerListView: { + id: 'networkProviders', + fields: { + name: { + label: 'label.name' + }, + state: { + label: 'label.state', + converter: function (str) { + // For localization + return str; + }, + indicator: { + 'Enabled': 'on', + 'Disabled': 'off' + } + } + }, + disableInfiniteScrolling: true, + dataProvider: function (args) { + refreshNspData(); + args.response.success({ + data: nspHardcodingArray + }) + }, + + detailView: function (args) { + return cloudStack.sections.system.naas.networkProviders.types[ + args.context.networkProviders[0].id]; + } + }, + mainNetworks: { + 'public': { + detailView: { + actions: { + edit: { + label: 'label.edit', + action: function (args) { + var trafficType = getTrafficType(selectedPhysicalNetworkObj, 'Public'); + + updateTrafficLabels(trafficType, args.data, function () { + args.response.success(); + }); + } + } + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + traffictype: { + label: 'label.traffic.type' + }, + broadcastdomaintype: { + label: 'label.broadcast.domain.type' + } + }, + { + xennetworklabel: { + label: 'label.xenserver.traffic.label', + isEditable: true + }, + kvmnetworklabel: { + label: 'label.kvm.traffic.label', + isEditable: true + }, + vmwarenetworklabel: { + label: 'label.vmware.traffic.label', + isEditable: true + }, + ovmnetworklabel: { + label: 'label.ovm.traffic.label', + isEditable: true + }, + lxcnetworklabel: { + label: 'label.lxc.traffic.label', + isEditable: true + }, + hypervnetworklabel: { + label: 'label.hyperv.traffic.label', + isEditable: true + }, + ovm3networklabel: { + label: 'label.ovm3.traffic.label', + isEditable: true + } + }], + + dataProvider: function (args) { + $.ajax({ + url: createURL("listNetworks&listAll=true&trafficType=Public&isSystem=true&zoneId=" + selectedZoneObj.id, { + ignoreProject: true + }), + dataType: "json", + async: false, + success: function (json) { + var trafficType = getTrafficType(selectedPhysicalNetworkObj, 'Public'); + var items = json.listnetworksresponse.network; + + selectedPublicNetworkObj = items[0]; + + // Include traffic labels + selectedPublicNetworkObj.xennetworklabel = trafficType.xennetworklabel; + selectedPublicNetworkObj.kvmnetworklabel = trafficType.kvmnetworklabel; + selectedPublicNetworkObj.vmwarenetworklabel = trafficType.vmwarenetworklabel; + selectedPublicNetworkObj.ovmnetworklabel = trafficType.ovmnetworklabel; + selectedPublicNetworkObj.lxcnetworklabel = trafficType.lxcnetworklabel; + selectedPublicNetworkObj.hypervnetworklabel = trafficType.hypervnetworklabel; + selectedPublicNetworkObj.ovm3networklabel = trafficType.ovm3networklabel; + args.response.success({ + data: selectedPublicNetworkObj + }); + } + }); + } + }, + + ipAddresses: { + title: 'label.ip.ranges', + custom: function (args) { + return $('
    ').multiEdit({ + context: args.context, + noSelect: true, + fields: { + 'gateway': { + edit: true, + label: 'label.gateway' + }, + 'netmask': { + edit: true, + label: 'label.netmask' + }, + 'vlan': { + edit: true, + label: 'label.vlan', + isOptional: true + }, + 'startip': { + edit: true, + label: 'label.start.IP' + }, + 'endip': { + edit: true, + label: 'label.end.IP' + }, + 'account': { + label: 'label.account', + custom: { + buttonLabel: 'label.set.reservation', + action: cloudStack.publicIpRangeAccount.dialog() + } + }, + 'add-rule': { + label: 'label.add', + addButton: true + } + }, + add: { + label: 'label.add', + action: function (args) { + var array1 =[]; + array1.push("&zoneId=" + args.context.zones[0].id); + + var vlan = "untagged"; + if (args.data.vlan != null && args.data.vlan.length > 0){ + vlan = args.data.vlan; + } + cloudStack.addVlanToCommandUrlParameterArrayIfItIsNotNullAndNotEmpty(array1, vlan); + + array1.push("&gateway=" + args.data.gateway); + array1.push("&netmask=" + args.data.netmask); + array1.push("&startip=" + args.data.startip); + if (args.data.endip != null && args.data.endip.length > 0) + array1.push("&endip=" + args.data.endip); + + if (args.data.account) { + if (args.data.account.account) + array1.push("&account=" + args.data.account.account); + if (args.data.account.domainid) { + array1.push("&domainid=" + args.data.account.domainid); + } + if (args.data.account.systemvms) { + systvmsval = args.data.account.systemvms == "on" ? "true" : "false" + array1.push("&forsystemvms=" + systvmsval); + } + } + + array1.push("&forVirtualNetwork=true"); + //indicates this new IP range is for public network, not guest network + + $.ajax({ + url: createURL("createVlanIpRange" + array1.join("")), + dataType: "json", + success: function (json) { + var item = json.createvlaniprangeresponse.vlan; + args.response.success({ + data: item, + notification: { + label: 'label.add.ip.range', + poll: function (args) { + args.complete(); + } + } + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + } + }, + actionPreFilter: function (args) { + var actionsToShow =[ 'destroy']; + if (args.context.multiRule[0].domain == 'ROOT' && args.context.multiRule[0].account != null && + args.context.multiRule[0].account.account == 'system' && !args.context.multiRule[0].forsystemvms) + actionsToShow.push('addAccount'); else + actionsToShow.push('releaseFromAccount'); + return actionsToShow; + }, + actions: { + destroy: { + label: 'label.remove.ip.range', + action: function (args) { + $.ajax({ + url: createURL('deleteVlanIpRange&id=' + args.context.multiRule[0].id), + dataType: 'json', + async: true, + success: function (json) { + args.response.success({ + notification: { + label: 'label.remove.ip.range', + poll: function (args) { + args.complete(); + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + }, + + releaseFromAccount: { + label: 'label.release.account', + action: function (args) { + $.ajax({ + url: createURL('releasePublicIpRange'), + data: { + id: args.context.multiRule[0].id + }, + success: function (json) { + args.response.success({ + notification: { + label: 'label.release.account.lowercase', + poll: function (args) { + args.complete(); + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + }, + + addAccount: { + label: 'label.add.account', + createForm: { + title: 'label.add.account', + fields: { + account: { + label: 'label.account' + }, + domainid: { + label: 'label.domain', + select: function (args) { + $.ajax({ + url: createURL('listDomains'), + data: { + details: 'min', + listAll: true + }, + success: function (json) { + args.response.success({ + data: $.map(json.listdomainsresponse.domain, function (domain) { + return { + id: domain.id, + description: domain.path + }; + }) + }); + } + }); + } + } + } + }, + action: function (args) { + var data = { + id: args.context.multiRule[0].id, + zoneid: args.context.multiRule[0].zoneid, + domainid: args.data.domainid + }; + if (args.data.account) { + $.extend(data, { + account: args.data.account + }); + } + $.ajax({ + url: createURL('dedicatePublicIpRange'), + data: data, + success: function (json) { + args.response.success({ + notification: { + label: 'label.add.account', + poll: function (args) { + args.complete(); + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL("listVlanIpRanges&zoneid=" + args.context.zones[0].id + "&networkId=" + selectedPublicNetworkObj.id), + dataType: "json", + success: function (json) { + var items = json.listvlaniprangesresponse.vlaniprange; + + args.response.success({ + data: $.map(items, function (item) { + return $.extend(item, { + account: { + _buttonLabel: item.account ? '[' + item.domain + '] ' + item.account: item.domain, + account: item.account, + domainid: item.domainid, + forSystemVms: item.forsystemvms + } + }); + }) + }); + } + }); + } + }); + } + } + } + } + }, + + 'storage': { + detailView: { + actions: { + edit: { + label: 'label.edit', + action: function (args) { + var trafficType = getTrafficType(selectedPhysicalNetworkObj, 'Storage'); + + updateTrafficLabels(trafficType, args.data, function () { + args.response.success(); + }); + } + } + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + traffictype: { + label: 'label.traffic.type' + }, + broadcastdomaintype: { + label: 'label.broadcast.domain.type' + } + }, + { + xennetworklabel: { + label: 'label.xenserver.traffic.label', + isEditable: true + }, + kvmnetworklabel: { + label: 'label.kvm.traffic.label', + isEditable: true + }, + vmwarenetworklabel: { + label: 'label.vmware.traffic.label', + isEditable: true + }, + ovmnetworklabel: { + label: 'label.ovm.traffic.label', + isEditable: true + }, + lxcnetworklabel: { + label: 'label.lxc.traffic.label', + isEditable: true + }, + hypervnetworklabel: { + label: 'label.hyperv.traffic.label', + isEditable: true + }, + ovm3networklabel: { + label: 'label.ovm3.traffic.label', + isEditable: true + } + }], + + dataProvider: function (args) { + $.ajax({ + url: createURL("listNetworks&listAll=true&trafficType=Storage&isSystem=true&zoneId=" + selectedZoneObj.id), + dataType: "json", + async: false, + success: function (json) { + var items = json.listnetworksresponse.network; + var trafficType = getTrafficType(selectedPhysicalNetworkObj, 'Storage'); + selectedPublicNetworkObj = items[0]; + + selectedPublicNetworkObj.xennetworklabel = trafficType.xennetworklabel; + selectedPublicNetworkObj.kvmnetworklabel = trafficType.kvmnetworklabel; + selectedPublicNetworkObj.vmwarenetworklabel = trafficType.vmwarenetworklabel; + selectedPublicNetworkObj.ovmnetworklabel = trafficType.ovmnetworklabel; + selectedPublicNetworkObj.lxcnetworklabel = trafficType.lxcnetworklabel; + selectedPublicNetworkObj.hypervnetworklabel = trafficType.hypervnetworklabel; + selectedPublicNetworkObj.ovm3networklabel = trafficType.ovm3networklabel; + args.response.success({ + data: selectedPublicNetworkObj + }); + } + }); + } + }, + + ipAddresses: { + title: 'label.ip.ranges', + custom: function (args) { + return $('
    ').multiEdit({ + context: args.context, + noSelect: true, + fields: { + 'podid': { + label: 'label.pod', + select: function (args) { + $.ajax({ + url: createURL("listPods&zoneid=" + selectedZoneObj.id), + dataType: "json", + success: function (json) { + var items =[]; + var pods = json.listpodsresponse.pod; + $(pods).each(function () { + items.push({ + name: this.id, + description: this.name + }); + //should be "{id: this.id, description: this.name}" (to be consistent with dropdown in createFrom and edit mode) (Brian will fix widget later) + }); + args.response.success({ + data: items + }); + } + }); + } + }, + 'gateway': { + edit: true, + label: 'label.gateway' + }, + 'netmask': { + edit: true, + label: 'label.netmask' + }, + 'vlan': { + edit: true, + label: 'label.vlan', + isOptional: true + }, + 'startip': { + edit: true, + label: 'label.start.IP' + }, + 'endip': { + edit: true, + label: 'label.end.IP' + }, + 'add-rule': { + label: 'label.add', + addButton: true + } + }, + add: { + label: 'label.add', + action: function (args) { + var array1 =[]; + array1.push("&zoneId=" + args.context.zones[0].id); + array1.push("&podid=" + args.data.podid); + array1.push("&gateway=" + args.data.gateway); + + cloudStack.addVlanToCommandUrlParameterArrayIfItIsNotNullAndNotEmpty(array1, args.data.vlan); + + array1.push("&netmask=" + args.data.netmask); + array1.push("&startip=" + args.data.startip); + if (args.data.endip != null && args.data.endip.length > 0) + array1.push("&endip=" + args.data.endip); + + $.ajax({ + url: createURL("createStorageNetworkIpRange" + array1.join("")), + dataType: "json", + success: function (json) { + args.response.success({ + _custom: { + jobId: json.createstoragenetworkiprangeresponse.jobid + }, + notification: { + label: 'label.add.ip.range', + poll: pollAsyncJobResult + } + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + } + }, + actions: { + destroy: { + label: 'label.delete', + action: function (args) { + $.ajax({ + url: createURL('deleteStorageNetworkIpRange&id=' + args.context.multiRule[0].id), + dataType: 'json', + async: true, + success: function (json) { + args.response.success({ + notification: { + label: 'label.remove.ip.range', + poll: function (args) { + args.complete(); + } + } + }); + } + }); + } + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL("listStorageNetworkIpRange&zoneid=" + args.context.zones[0].id), + dataType: "json", + success: function (json) { + var items = json.liststoragenetworkiprangeresponse.storagenetworkiprange; + args.response.success({ + data: items + }); + } + }); + } + }); + } + } + } + } + }, + + 'management': { + detailView: { + actions: { + edit: { + label: 'label.edit', + action: function (args) { + var trafficType = getTrafficType(selectedPhysicalNetworkObj, 'Management'); + + updateTrafficLabels(trafficType, args.data, function () { + args.response.success(); + }); + } + } + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + traffictype: { + label: 'label.traffic.type' + }, + broadcastdomaintype: { + label: 'label.broadcast.domain.type' + } + }, + { + xennetworklabel: { + label: 'label.xenserver.traffic.label', + isEditable: true + }, + kvmnetworklabel: { + label: 'label.kvm.traffic.label', + isEditable: true + }, + vmwarenetworklabel: { + label: 'label.vmware.traffic.label', + isEditable: true + }, + ovmnetworklabel: { + label: 'label.ovm.traffic.label', + isEditable: true + }, + lxcnetworklabel: { + label: 'label.lxc.traffic.label', + isEditable: true + }, + hypervnetworklabel: { + label: 'label.hyperv.traffic.label', + isEditable: true + }, + ovm3networklabel: { + label: 'label.ovm3.traffic.label', + isEditable: true + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listNetworks&listAll=true&issystem=true&trafficType=Management&zoneId=" + selectedZoneObj.id), + dataType: "json", + success: function (json) { + selectedManagementNetworkObj = json.listnetworksresponse.network[0]; + + var trafficType = getTrafficType(selectedPhysicalNetworkObj, 'Management'); + + selectedManagementNetworkObj.xennetworklabel = trafficType.xennetworklabel; + selectedManagementNetworkObj.kvmnetworklabel = trafficType.kvmnetworklabel; + selectedManagementNetworkObj.vmwarenetworklabel = trafficType.vmwarenetworklabel; + selectedManagementNetworkObj.ovmnetworklabel = trafficType.ovmnetworklabel; + selectedManagementNetworkObj.lxcnetworklabel = trafficType.lxcnetworklabel; + selectedManagementNetworkObj.hypervnetworklabel = trafficType.hypervnetworklabel; + selectedManagementNetworkObj.ovm3networklabel = trafficType.ovm3networklabel; + args.response.success({ + data: selectedManagementNetworkObj + }); + } + }); + } + }, + + ipAddresses: { + title: 'label.ip.ranges', + custom: function (args) { + return $('
    ').multiEdit({ + context: args.context, + noSelect: true, + fields: { + 'podid': { + label: 'label.pod', + select: function (args) { + $.ajax({ + url: createURL("listPods&zoneid=" + selectedZoneObj.id), + dataType: "json", + success: function (json) { + var items =[]; + var pods = json.listpodsresponse.pod; + $(pods).each(function () { + items.push({ + name: this.id, + description: this.name + }); + }); + args.response.success({ + data: items + }); + } + }); + } + }, + 'gateway': { + edit: true, + label: 'label.gateway' + }, + 'netmask': { + edit: true, + label: 'label.netmask' + }, + 'vlan': { + edit: true, + label: 'label.vlan', + validation: { + required: false + } + }, + 'startip': { + edit: true, + label: 'label.start.IP' + }, + 'endip': { + edit: true, + label: 'label.end.IP', + validation: { + required: false + } + }, + 'systemvms' : { + isBoolean: true, + label: 'label.system.vms' + }, + 'add-rule': { + label: 'label.add', + addButton: true + } + }, + add: { + label: 'label.add', + action: function (args) { + var array1 =[]; + + array1.push("&podid=" + args.data.podid); + array1.push("&gateway=" + args.data.gateway); + array1.push("&netmask=" + args.data.netmask); + array1.push("&startip=" + args.data.startip); + + if (args.data.endip != null && args.data.endip.length > 0) + array1.push("&endip=" + args.data.endip); + + if (args.data.systemvms) { + array1.push("&forsystemvms=" + (args.data.systemvms == "on" ? "true" : "false")); + } + cloudStack.addVlanToCommandUrlParameterArrayIfItIsNotNullAndNotEmpty(array1, args.data.vlan); + + $.ajax({ + url: createURL("createManagementNetworkIpRange" + array1.join("")), + dataType: "json", + success: function (json) { + args.response.success({ + _custom: { + jobId: json.createmanagementnetworkiprangeresponse.jobid + }, + notification: { + label: 'label.add.management.ip.range', + poll: pollAsyncJobResult + } + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + } + }, + actions: { + destroy: { + label: 'label.delete', + action: function (args) { + var array1 =[]; + array1.push("&podid=" + args.context.multiRule[0].podid); + array1.push("&startip=" + args.context.multiRule[0].startip); + array1.push("&endip=" + args.context.multiRule[0].endip); + array1.push("&vlan=" + args.context.multiRule[0].vlan); + + $.ajax({ + url: createURL('deleteManagementNetworkIpRange' + array1.join("")), + dataType: 'json', + async: true, + success: function (json) { + args.response.success({ + _custom: { + jobId: json.deletemanagementnetworkiprangeresponse.jobid + }, + notification: { + label: 'label.remove.management.ip.range', + poll: pollAsyncJobResult + } + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + } + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL("listPods&zoneid=" + selectedZoneObj.id), + dataType: "json", + async: true, + success: function (json) { + var items =[]; + + var pods = json.listpodsresponse.pod; + $(pods).each(function () { + for (var i = 0; i < this.startip.length; i++) { + var systemvmsValue = this.forsystemvms[i] == "1" ? true : false; + items.push({ + podid: this.id, + gateway: this.gateway, + netmask: this.netmask, + startip: this.startip[i], + endip: this.endip[i], + systemvms: systemvmsValue, + vlan: this.vlanid[i] + }); + } + }); + + args.response.success({ + data: items + }); + } + }); + } + }); + } + } + } + } + }, + + 'guest': { + //physical network + Guest traffic type + detailView: { + actions: { + edit: { + label: 'label.edit', + action: function (args) { + var data = { + id: selectedPhysicalNetworkObj.id + }; + + $.extend(data, { + vlan: args.data.vlan + }); + + $.extend(data, { + tags: args.data.tags + }); + + $.ajax({ + url: createURL('updatePhysicalNetwork'), + data: data, + success: function (json) { + var jobId = json.updatephysicalnetworkresponse.jobid; + + var trafficType = getTrafficType(selectedPhysicalNetworkObj, 'Guest'); + + updateTrafficLabels(trafficType, args.data, function () { + args.response.success({ + _custom: { + jobId: jobId + } + }); + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + + tabFilter: function (args) { + var hiddenTabs =[]; + if (selectedZoneObj.networktype == 'Basic') { + hiddenTabs.push("network"); + hiddenTabs.push("dedicatedGuestVlanRanges"); + } else { + //selectedZoneObj.networktype == 'Advanced' + hiddenTabs.push("ipAddresses"); + } + return hiddenTabs; + }, + + tabs: { + details: { + title: 'label.details', + preFilter: function (args) { + var hiddenFields =[]; + if (selectedZoneObj.networktype == "Basic") { + hiddenFields.push("vlan"); + // hiddenFields.push("endVlan"); + } + return hiddenFields; + }, + fields:[ { + //updatePhysicalNetwork API + state: { + label: 'label.state' + }, + vlan: { + label: 'label.vlan.vni.ranges', + isEditable: true + }, + tags: { + label: 'label.tags', + isEditable: true + }, + broadcastdomainrange: { + label: 'label.broadcast.domain.range' + } + }, + { + //updateTrafficType API + xennetworklabel: { + label: 'label.xenserver.traffic.label', + isEditable: true + }, + kvmnetworklabel: { + label: 'label.kvm.traffic.label', + isEditable: true + }, + vmwarenetworklabel: { + label: 'label.vmware.traffic.label', + isEditable: true + }, + ovmnetworklabel: { + label: 'label.ovm.traffic.label', + isEditable: true + }, + lxcnetworklabel: { + label: 'label.lxc.traffic.label', + isEditable: true + }, + hypervnetworklabel: { + label: 'label.hyperv.traffic.label', + isEditable: true + }, + ovm3networklabel: { + label: 'label.ovm3.traffic.label', + isEditable: true + } + }], + dataProvider: function (args) { + //physical network + Guest traffic type + //refresh physical network + $.ajax({ + url: createURL('listPhysicalNetworks'), + data: { + id: args.context.physicalNetworks[0].id + }, + async: true, + success: function (json) { + selectedPhysicalNetworkObj = json.listphysicalnetworksresponse.physicalnetwork[0]; + + // var startVlan, endVlan; + var vlan = selectedPhysicalNetworkObj.vlan; + /* if(vlan != null && vlan.length > 0) { + if(vlan.indexOf("-") != -1) { + var vlanArray = vlan.split("-"); + startVlan = vlanArray[0]; + endVlan = vlanArray[1]; + } + else { + startVlan = vlan; + } + selectedPhysicalNetworkObj["startVlan"] = startVlan; + selectedPhysicalNetworkObj["endVlan"] = endVlan; + }*/ + + //traffic type + var xenservertrafficlabel, kvmtrafficlabel, vmwaretrafficlabel; + var trafficType = getTrafficType(selectedPhysicalNetworkObj, 'Guest'); + //refresh Guest traffic type + selectedPhysicalNetworkObj[ "xennetworklabel"] = trafficType.xennetworklabel; + selectedPhysicalNetworkObj[ "kvmnetworklabel"] = trafficType.kvmnetworklabel; + selectedPhysicalNetworkObj[ "vmwarenetworklabel"] = trafficType.vmwarenetworklabel; + selectedPhysicalNetworkObj[ "ovmnetworklabel"] = trafficType.ovmnetworklabel; + selectedPhysicalNetworkObj[ "lxcnetworklabel"] = trafficType.lxcnetworklabel; + selectedPhysicalNetworkObj[ "hypervnetworklabel"] = trafficType.hypervnetworklabel; + selectedPhysicalNetworkObj[ "ovm3networklabel"] = trafficType.ovm3networklabel; + args.response.success({ + actionFilter: function () { + var allowedActions =[ 'edit', 'addVlanRange', 'removeVlanRange']; + return allowedActions; + }, + data: selectedPhysicalNetworkObj + }); + } + }); + } + }, + + ipAddresses: { + title: 'label.ip.ranges', + custom: function (args) { + return $('
    ').multiEdit({ + context: args.context, + noSelect: true, + fields: { + 'podid': { + label: 'label.pod', + select: function (args) { + $.ajax({ + url: createURL("listPods&zoneid=" + selectedZoneObj.id), + dataType: "json", + success: function (json) { + var items =[]; + var pods = json.listpodsresponse.pod; + $(pods).each(function () { + items.push({ + name: this.id, + description: this.name + }); + //should be "{id: this.id, description: this.name}" (to be consistent with dropdown in createFrom and edit mode) (Brian will fix widget later) + }); + args.response.success({ + data: items + }); + } + }); + } + }, + 'gateway': { + edit: true, + label: 'label.gateway' + }, + 'netmask': { + edit: true, + label: 'label.netmask' + }, + 'startip': { + edit: true, + label: 'label.start.IP' + }, + 'endip': { + edit: true, + label: 'label.end.IP' + }, + 'add-rule': { + label: 'label.add', + addButton: true + } + }, + add: { + label: 'label.add', + action: function (args) { + var array1 =[]; + array1.push("&podid=" + args.data.podid); + array1.push("&networkid=" + selectedGuestNetworkObj.id); + array1.push("&gateway=" + args.data.gateway); + array1.push("&netmask=" + args.data.netmask); + array1.push("&startip=" + args.data.startip); + if (args.data.endip != null && args.data.endip.length > 0) + array1.push("&endip=" + args.data.endip); + array1.push("&forVirtualNetwork=false"); + //indicates this new IP range is for guest network, not public network + + $.ajax({ + url: createURL("createVlanIpRange" + array1.join("")), + dataType: "json", + success: function (json) { + var item = json.createvlaniprangeresponse.vlan; + args.response.success({ + data: item, + notification: { + label: 'label.add.ip.range', + poll: function (args) { + args.complete(); + } + } + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + } + }, + actions: { + destroy: { + label: 'label.remove.ip.range', + action: function (args) { + $.ajax({ + url: createURL('deleteVlanIpRange&id=' + args.context.multiRule[0].id), + dataType: 'json', + async: true, + success: function (json) { + args.response.success({ + notification: { + label: 'label.remove.ip.range', + poll: function (args) { + args.complete(); + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + }, + dataProvider: function (args) { + //only basic zone has IP Range tab + selectedGuestNetworkObj = null; + $.ajax({ + url: createURL("listNetworks&listAll=true&trafficType=Guest&zoneid=" + selectedZoneObj.id), + dataType: "json", + async: false, + success: function (json) { + var items = json.listnetworksresponse.network; + if (items != null && items.length > 0) + selectedGuestNetworkObj = json.listnetworksresponse.network[0]; + } + }); + if (selectedGuestNetworkObj == null) + return; + + $.ajax({ + url: createURL("listVlanIpRanges&zoneid=" + selectedZoneObj.id + "&networkId=" + selectedGuestNetworkObj.id), + dataType: "json", + success: function (json) { + var items = json.listvlaniprangesresponse.vlaniprange; + args.response.success({ + data: items + }); + } + }); + } + }); + } + }, + + network: { + title: 'label.network', + listView: { + section: 'networks', + id: 'networks', + fields: { + name: { + label: 'label.name' + }, + type: { + label: 'label.type' + }, + vlan: { + label: 'label.vnet.id' + }, + broadcasturi: { + label: 'label.broadcat.uri' + }, + cidr: { + label: 'label.ipv4.cidr' + }, + ip6cidr: { + label: 'label.ipv6.CIDR' + } + //scope: { label: 'label.scope' } + }, + actions: { + add: addGuestNetworkDialog.def + }, + + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + + //need to make 2 listNetworks API call to get all guest networks from one physical network in Advanced zone + var items =[]; + //"listNetworks&projectid=-1": list guest networks under all projects (no matter who the owner is) + $.ajax({ + url: createURL("listNetworks&projectid=-1&trafficType=Guest&zoneId=" + selectedZoneObj.id + "&physicalnetworkid=" + selectedPhysicalNetworkObj.id + "&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + dataType: "json", + async: false, + success: function (json) { + if (json.listnetworksresponse.network != null && json.listnetworksresponse.network.length > 0) + items = json.listnetworksresponse.network; + } + }); + + var networkCollectionMap = { + }; + $(items).each(function () { + networkCollectionMap[ this.id] = this.name; + }); + + //"listNetworks&listAll=true: list guest networks that are not under any project (no matter who the owner is) + $.ajax({ + url: createURL("listNetworks&listAll=true&trafficType=Guest&zoneId=" + selectedZoneObj.id + "&physicalnetworkid=" + selectedPhysicalNetworkObj.id + "&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + dataType: "json", + async: false, + success: function (json) { + $(json.listnetworksresponse.network).each(function () { + if ((this.id in networkCollectionMap) == false) + items.push(this); + }); + } + }); + + $(items).each(function () { + addExtraPropertiesToGuestNetworkObject(this); + }); + + args.response.success({ + data: items + }); + }, + + detailView: { + name: 'label.guest.network.details', + noCompact: true, + viewAll: { + path: '_zone.guestIpRanges', + label: 'label.ip.ranges', + preFilter: function (args) { + if (selectedGuestNetworkObj.type == "Isolated") { + var services = selectedGuestNetworkObj.service; + if (services != null) { + for (var i = 0; i < services.length; i++) { + var service = services[i]; + if (service.name == "SourceNat") + return false; + } + } + } + return true; + } + }, + actions: { + edit: { + label: 'label.edit', + action: function (args) { + var array1 =[]; + array1.push("&name=" + encodeURIComponent(args.data.name)); + array1.push("&displaytext=" + encodeURIComponent(args.data.displaytext)); + + //args.data.networkdomain is null when networkdomain field is hidden + if (args.data.networkdomain != null && args.data.networkdomain != selectedGuestNetworkObj.networkdomain) + array1.push("&networkdomain=" + encodeURIComponent(args.data.networkdomain)); + + //args.data.networkofferingid is null when networkofferingid field is hidden + if (args.data.networkofferingid != null && args.data.networkofferingid != args.context.networks[0].networkofferingid) { + array1.push("&networkofferingid=" + encodeURIComponent(args.data.networkofferingid)); + + if (args.context.networks[0].type == "Isolated") { + //Isolated network + cloudStack.dialog.confirm({ + message: 'message.confirm.current.guest.CIDR.unchanged', + action: function () { + //"Yes" button is clicked + array1.push("&changecidr=false"); + $.ajax({ + url: createURL("updateNetwork&id=" + args.context.networks[0].id + array1.join("")), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + var item = json.queryasyncjobresultresponse.jobresult.network; + return { + data: item + }; + } + } + }); + } + }); + }, + cancelAction: function () { + //"Cancel" button is clicked + array1.push("&changecidr=true"); + $.ajax({ + url: createURL("updateNetwork&id=" + args.context.networks[0].id + array1.join("")), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + var item = json.queryasyncjobresultresponse.jobresult.network; + return { + data: item + }; + } + } + }); + } + }); + } + }); + return; + } + } + + $.ajax({ + url: createURL("updateNetwork&id=" + args.context.networks[0].id + array1.join("")), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + var item = json.queryasyncjobresultresponse.jobresult.network; + return { + data: item + }; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + 'restart': { + label: 'label.restart.network', + createForm: { + title: 'label.restart.network', + desc: 'message.restart.network', + preFilter: function (args) { + if (selectedZoneObj.networktype == "Basic") { + args.$form.find('.form-item[rel=cleanup]').find('input').prop('checked', false); + //unchecked + args.$form.find('.form-item[rel=cleanup]').hide(); + //hidden + } else { + args.$form.find('.form-item[rel=cleanup]').find('input').attr('checked', 'checked'); + //checked + args.$form.find('.form-item[rel=cleanup]').css('display', 'inline-block'); + //shown + } + }, + fields: { + cleanup: { + label: 'label.clean.up', + isBoolean: true + } + } + }, + action: function (args) { + var array1 =[]; + array1.push("&cleanup=" + (args.data.cleanup == "on")); + $.ajax({ + url: createURL("restartNetwork&cleanup=true&id=" + args.context.networks[0].id + array1.join("")), + dataType: "json", + async: true, + success: function (json) { + var jid = json.restartnetworkresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.network; + } + } + }); + } + }); + }, + messages: { + notification: function (args) { + return 'label.restart.network'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + 'remove': { + label: 'label.action.delete.network', + messages: { + confirm: function (args) { + return 'message.action.delete.network'; + }, + notification: function (args) { + return 'label.action.delete.network'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("deleteNetwork&id=" + args.context.networks[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.deletenetworkresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return { + }; + //nothing in this network needs to be updated, in fact, this whole template has being deleted + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.details', + preFilter: function (args) { + var hiddenFields =[]; + if (selectedZoneObj.networktype == "Basic") { + hiddenFields.push("account"); + hiddenFields.push("gateway"); + //hiddenFields.push("netmask"); + } + + if (selectedGuestNetworkObj.type == "Isolated") { + hiddenFields.push("networkofferingdisplaytext"); + hiddenFields.push("networkdomaintext"); + hiddenFields.push("gateway"); + //hiddenFields.push("netmask"); + } else { + //selectedGuestNetworkObj.type == "Shared" + hiddenFields.push("networkofferingid"); + hiddenFields.push("networkdomain"); + } + return hiddenFields; + }, + fields:[ { + name: { + label: 'label.name', + isEditable: true + } + }, + { + id: { + label: 'label.id' + }, + displaytext: { + label: 'label.description', + isEditable: true + }, + type: { + label: 'label.type' + }, + state: { + label: 'label.state' + }, + restartrequired: { + label: 'label.restart.required', + converter: function (booleanValue) { + if (booleanValue == true) + return "Yes"; else if (booleanValue == false) + return "No"; + } + }, + vlan: { + label: 'label.vlan.id' + }, + broadcasturi: { + label: 'label.broadcat.uri' + }, + scope: { + label: 'label.scope' + }, + networkofferingdisplaytext: { + label: 'label.network.offering' + }, + networkofferingid: { + label: 'label.network.offering', + isEditable: true, + select: function (args) { + var items =[]; + $.ajax({ + url: createURL("listNetworkOfferings&state=Enabled&networkid=" + selectedGuestNetworkObj.id + "&zoneid=" + selectedGuestNetworkObj.zoneid), + dataType: "json", + async: false, + success: function (json) { + var networkOfferingObjs = json.listnetworkofferingsresponse.networkoffering; + $(networkOfferingObjs).each(function () { + items.push({ + id: this.id, + description: this.displaytext + }); + }); + } + }); + + //include currently selected network offeirng to dropdown + items.push({ + id: selectedGuestNetworkObj.networkofferingid, + description: selectedGuestNetworkObj.networkofferingdisplaytext + }); + + args.response.success({ + data: items + }); + } + }, + + networkofferingidText: { + label: 'label.network.offering.id' + }, + + gateway: { + label: 'label.ipv4.gateway' + }, + //netmask: { label: 'label.netmask' }, + cidr: { + label: 'label.ipv4.cidr' + }, + + ip6gateway: { + label: 'label.ipv6.gateway' + }, + ip6cidr: { + label: 'label.ipv6.CIDR' + }, + + networkdomaintext: { + label: 'label.network.domain' + }, + networkdomain: { + label: 'label.network.domain', + isEditable: true + }, + + domain: { + label: 'label.domain' + }, + subdomainaccess: { + label: 'label.subdomain.access', + converter: function (data) { + return data ? 'Yes': 'No'; + } + }, + account: { + label: 'label.account' + }, + project: { + label: 'label.project' + } + }], + dataProvider: function (args) { + var data = { + id: args.context.networks[0].id + }; + if (args.context.networks[0].projectid != null) { + $.extend(data, { + projectid: -1 + }); + } else { + $.extend(data, { + listAll: true //pass "&listAll=true" to "listNetworks&id=xxxxxxxx" for now before API gets fixed. + }); + } + + $.ajax({ + url: createURL("listNetworks"), + data: data, + async: false, + success: function (json) { + selectedGuestNetworkObj = json.listnetworksresponse.network[0]; + addExtraPropertiesToGuestNetworkObject(selectedGuestNetworkObj); + + $(window).trigger('cloudStack.module.sharedFunctions.addExtraProperties', { + obj: selectedGuestNetworkObj, + objType: "Network" + }); + + args.response.success({ + actionFilter: cloudStack.actionFilter.guestNetwork, + data: selectedGuestNetworkObj + }); + } + }); + } + } + } + } + } + }, + + dedicatedGuestVlanRanges: { + title: 'label.dedicated.vlan.vni.ranges', + listView: { + section: 'dedicatedGuestVlanRanges', + id: 'dedicatedGuestVlanRanges', + fields: { + guestvlanrange: { + label: 'label.vlan.vni.ranges' + }, + domain: { + label: 'label.domain' + }, + account: { + label: 'label.account' + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL('listDedicatedGuestVlanRanges'), + data: { + physicalnetworkid: args.context.physicalNetworks[0].id + }, + success: function (json) { + var items = json.listdedicatedguestvlanrangesresponse.dedicatedguestvlanrange; + args.response.success({ + data: items + }) + } + }); + }, + actions: { + add: { + label: 'label.dedicate.vlan.vni.range', + messages: { + notification: function (args) { + return 'label.dedicate.vlan.vni.range'; + } + }, + createForm: { + title: 'label.dedicate.vlan.vni.range', + fields: { + vlanrange: { + label: 'label.vlan.vni.range', + validation: { + required: true + } + }, + scope: { + label: 'label.scope', + docID: 'helpGuestNetworkZoneScope', + select: function(args) { + var array1 = []; + + array1.push({ + id: 'account-specific', + description: 'label.account' + }); + array1.push({ + id: 'project-specific', + description: 'label.project' + }); + + args.response.success({ + data: array1 + }); + + args.$select.change(function() { + var $form = $(this).closest('form'); + + if ($(this).val() == "account-specific") { + $form.find('.form-item[rel=domainId]').css('display', 'inline-block'); + $form.find('.form-item[rel=account]').css('display', 'inline-block'); + $form.find('.form-item[rel=projectId]').hide(); + } else if ($(this).val() == "project-specific") { + $form.find('.form-item[rel=domainId]').css('display', 'inline-block'); + $form.find('.form-item[rel=account]').hide(); + $form.find('.form-item[rel=projectId]').css('display', 'inline-block'); + } + + if (args.context.projects != null && args.context.projects.length > 0) { + $form.find('.form-item[rel=domainId]').hide(); + $form.find('.form-item[rel=account]').hide(); + $form.find('.form-item[rel=projectId]').hide(); + } + }); + }, + isHidden: function(args) { + if(args.context.projects != null && args.context.projects.length > 0) + return true; + else + return false; + } + }, + domainId: { + label: 'label.domain', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL('listDomains'), + data: { + details: 'min', + listAll: true + }, + success: function (json) { + args.response.success({ + data: $.map(json.listdomainsresponse.domain, function (domain) { + return { + id: domain.id, + description: domain.path + }; + }) + }); + } + }); + } + }, + account: { + label: 'label.account', + validation: { + required: true + }, + dependsOn: 'domainId', + select: function (args) { + $.ajax({ + url: createURL('listAccounts&domainid=' + args.domainId), + data: { + details: 'min', + listAll: true + }, + success: function (json) { + args.response.success({ + data: $.map(json.listaccountsresponse.account, function (account) { + return { + id: account.name, + description: account.name + }; + }) + }); + } + }); + } + }, + projectId: { + label: 'label.project', + validation: { + required: true + }, + dependsOn: 'domainId', + select: function(args) { + var items = []; + $.ajax({ + url: createURL("listProjects&details=min&domainid=" + args.domainId), + dataType: "json", + async: false, + success: function(json) { + projectObjs = json.listprojectsresponse.project; + $(projectObjs).each(function() { + items.push({ + id: this.id, + description: this.name + }); + }); + } + }); + args.response.success({ + data: items + }); + } + } + } + }, + action: function (args) { + var data = { + physicalnetworkid: args.context.physicalNetworks[0].id, + vlanrange: args.data.vlanrange + }; + + var $form = args.$form; + + if (($form.find('.form-item[rel=domainId]').css("display") != "none") && (args.data.domainId != null && args.data.domainId.length > 0)) { + $.extend(data, { + domainid: args.data.domainId + }) + } + + if (($form.find('.form-item[rel=account]').css("display") != "none") && (args.data.account != null && args.data.account.length > 0)) { + $.extend(data, { + account: args.data.account + }) + } + + if (($form.find('.form-item[rel=projectId]').css("display") != "none") && (args.data.projectId != null && args.data.projectId.length > 0)) { + $.extend(data, { + projectid: args.data.projectId + }) + } + + $.ajax({ + url: createURL('dedicateGuestVlanRange'), + data: data, + success: function (json) { + var item = json.dedicateguestvlanrangeresponse.dedicatedguestvlanrange; + args.response.success({ + data: item + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + } + }, + + detailView: { + name: 'label.vlan.range.details', + actions: { + remove: { + label: 'label.release.dedicated.vlan.range', + messages: { + confirm: function (args) { + return 'message.confirm.release.dedicate.vlan.range'; + }, + notification: function (args) { + return 'label.release.dedicated.vlan.range'; + } + }, + action: function (args) { + var data = { + id: args.context.dedicatedGuestVlanRanges[0].id + }; + $.ajax({ + url: createURL('releaseDedicatedGuestVlanRange'), + data: data, + async: true, + success: function (json) { + var jid = json.releasededicatedguestvlanrangeresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + + tabs: { + details: { + title: 'label.details', + fields:[ { + guestvlanrange: { + label: 'label.vlan.ranges' + } + }, + { + domain: { + label: 'label.domain' + }, + account: { + label: 'label.account' + }, + id: { + label: 'label.id' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL('listDedicatedGuestVlanRanges'), + data: { + id: args.context.dedicatedGuestVlanRanges[0].id + }, + success: function (json) { + var item = json.listdedicatedguestvlanrangesresponse.dedicatedguestvlanrange[0]; + args.response.success({ + data: item + }); + } + }); + } + } + } + } + } + } + } + } + } + }, + + networks: { + listView: { + id: 'physicalNetworks', + hideToolbar: true, + fields: { + name: { + label: 'label.name' + }, + state: { + converter: function (str) { + // For localization + return str; + }, + label: 'label.state', + indicator: { + 'Enabled': 'on', + 'Disabled': 'off' + } + }, + isolationmethods: { + label: 'label.isolation.method' + }, + vlan: { + label: 'label.vlan' + }, + broadcastdomainrange: { + label: 'label.broadcast.domain.range' + } + }, + + actions: { + remove: { + label: 'label.action.delete.physical.network', + messages: { + confirm: function (args) { + return 'message.action.delete.physical.network'; + }, + notification: function (args) { + return 'label.action.delete.physical.network'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("deletePhysicalNetwork&id=" + args.context.physicalNetworks[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.deletephysicalnetworkresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL('listPhysicalNetworks'), + data: { + zoneid: args.context.zones[0].id + }, + success: function (json) { + physicalNetworkObjs = json.listphysicalnetworksresponse.physicalnetwork; + args.response.success({ + actionFilter: cloudStack.actionFilter.physicalNetwork, + data: json.listphysicalnetworksresponse.physicalnetwork + }); + } + }); + } + }, + + trafficTypes: { + dataProvider: function (args) { + selectedPhysicalNetworkObj = args.context.physicalNetworks[0]; + + $.ajax({ + url: createURL('listTrafficTypes'), + data: { + physicalnetworkid: selectedPhysicalNetworkObj.id + }, + success: function (json) { + args.response.success({ + data: $.map(json.listtraffictypesresponse.traffictype, function (trafficType) { + return { + id: trafficType.id, + name: trafficType.traffictype + }; + }) + }); + } + }); + } + }, + + networkProviders: { + statusLabels: { + enabled: 'Enabled', //having device, network service provider is enabled + 'not-configured': 'Not setup', //no device + disabled: 'Disabled' //having device, network service provider is disabled + }, + + // Actions performed on entire net. provider type + actions: { + enable: function (args) { + args.response.success(); + }, + + disable: function (args) { + args.response.success(); + } + }, + + types: { + virtualRouter: { + id: 'virtualRouterProviders', + label: 'label.virtual.router', + isMaximized: true, + type: 'detailView', + fields: { + name: { + label: 'label.name' + }, + ipaddress: { + label: 'label.ip.address' + }, + state: { + label: 'label.status', + indicator: { + 'Enabled': 'on' + } + } + }, + tabs: { + network: { + title: 'label.network', + fields:[ { + name: { + label: 'label.name' + } + }, + { + id: { + label: 'label.id' + }, + state: { + label: 'label.state' + }, + physicalnetworkid: { + label: 'label.physical.network.ID' + }, + destinationphysicalnetworkid: { + label: 'label.destination.physical.network.id' + }, + supportedServices: { + label: 'label.supported.services' + } + }], + dataProvider: function (args) { + refreshNspData("VirtualRouter"); + args.response.success({ + actionFilter: virtualRouterProviderActionFilter, + data: $.extend(nspMap[ "virtualRouter"], { + supportedServices: nspMap[ "virtualRouter"].servicelist.join(', ') + }) + }); + } + }, + + instances: { + title: 'label.instances', + listView: { + label: 'label.virtual.appliances', + id: 'routers', + fields: { + name: { + label: 'label.name' + }, + zonename: { + label: 'label.zone' + }, + routerType: { + label: 'label.type' + }, + state: { + converter: function (str) { + // For localization + return str; + }, + label: 'label.status', + indicator: { + 'Running': 'on', + 'Stopped': 'off', + 'Error': 'off' + } + } + }, + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + + var data2 = { + forvpc: false + }; + var routers =[]; + $.ajax({ + url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + data: data2, + success: function (json) { + var items = json.listroutersresponse.router ? + json.listroutersresponse.router:[]; + + $(items).map(function (index, item) { + routers.push(item); + }); + + /* + * In project view, the first listRotuers API(without projectid=-1) will return the same objects as the second listRouters API(with projectid=-1), + * because in project view, all API calls are appended with projectid=[projectID]. + * Therefore, we only call the second listRouters API(with projectid=-1) in non-project view. + */ + if (cloudStack.context && cloudStack.context.projects == null) { //non-project view + $.ajax({ + url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&page=" + args.page + "&pagesize=" + pageSize + array1.join("") + "&projectid=-1"), + data: data2, + async: false, + success: function (json) { + var items = json.listroutersresponse.router ? + json.listroutersresponse.router:[]; + + $(items).map(function (index, item) { + routers.push(item); + }); + } + }); + } + + args.response.success({ + actionFilter: routerActionfilter, + data: $(routers).map(mapRouterType) + }); + } + }); + }, + detailView: { + name: 'label.virtual.appliance.details', + actions: { + start: { + label: 'label.action.start.router', + messages: { + confirm: function (args) { + return 'message.action.start.router'; + }, + notification: function (args) { + return 'label.action.start.router'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('startRouter&id=' + args.context.routers[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.startrouterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.router; + }, + getActionFilter: function () { + return routerActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + stop: { + label: 'label.action.stop.router', + createForm: { + title: 'label.action.stop.router', + desc: 'message.action.stop.router', + fields: { + forced: { + label: 'force.stop', + isBoolean: true, + isChecked: false + } + } + }, + messages: { + notification: function (args) { + return 'label.action.stop.router'; + } + }, + action: function (args) { + var array1 =[]; + array1.push("&forced=" + (args.data.forced == "on")); + $.ajax({ + url: createURL('stopRouter&id=' + args.context.routers[0].id + array1.join("")), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.stoprouterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.router; + }, + getActionFilter: function () { + return routerActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + 'remove': { + label: 'label.destroy.router', + messages: { + confirm: function (args) { + if (args && args.context && args.context.routers[0]) { + if (args.context.routers[0].state == 'Running') { + return dictionary['message.action.stop.router'] + ' ' + dictionary['message.confirm.destroy.router']; + } + } + return 'message.confirm.destroy.router'; + }, + notification: function (args) { + return 'label.destroy.router'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("destroyRouter&id=" + args.context.routers[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.destroyrouterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + migrate: { + label: 'label.action.migrate.router', + createForm: { + title: 'label.action.migrate.router', + desc: '', + fields: { + hostId: { + label: 'label.host', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL("findHostsForMigration&VirtualMachineId=" + args.context.routers[0].id), + dataType: "json", + async: true, + success: function (json) { + var hostObjs = json.findhostsformigrationresponse.host; + var items =[]; + $(hostObjs).each(function () { + items.push({ + id: this.id, + description: (this.name + " (" + (this.suitableformigration ? "Suitable": "Not Suitable") + ")") + }); + }); + args.response.success({ + data: items + }); + } + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + } + } + }, + messages: { + notification: function (args) { + return 'label.action.migrate.router'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("migrateSystemVm&hostid=" + args.data.hostId + "&virtualmachineid=" + args.context.routers[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.migratesystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + //return json.queryasyncjobresultresponse.jobresult.systemvminstance; //not all properties returned in systemvminstance + $.ajax({ + url: createURL("listRouters&id=" + json.queryasyncjobresultresponse.jobresult.systemvm.id), + dataType: "json", + async: false, + success: function (json) { + var items = json.listroutersresponse.router; + if (items != null && items.length > 0) { + return items[0]; + } + } + }); + }, + getActionFilter: function () { + return routerActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + viewConsole: { + label: 'label.view.console', + action: { + externalLink: { + url: function (args) { + return clientConsoleUrl + '?cmd=access&vm=' + args.context.routers[0].id; + }, + title: function (args) { + return args.context.routers[0].id.substr(0, 8); + //title in window.open() can't have space nor longer than 8 characters. Otherwise, IE browser will have error. + }, + width: 820, + height: 640 + } + } + } + }, + tabs: { + details: { + title: 'label.details', + preFilter: function (args) { + var hiddenFields =[]; + if (! args.context.routers[0].project) { + hiddenFields.push('project'); + hiddenFields.push('projectid'); + } + if (selectedZoneObj.networktype == 'Basic') { + hiddenFields.push('publicip'); + //In Basic zone, guest IP is public IP. So, publicip is not returned by listRouters API. Only guestipaddress is returned by listRouters API. + } + + if ('routers' in args.context && args.context.routers[0].vpcid != undefined) { + hiddenFields.push('guestnetworkid'); + hiddenFields.push('guestnetworkname'); + } else if ('routers' in args.context && args.context.routers[0].guestnetworkid != undefined) { + hiddenFields.push('vpcid'); + hiddenFields.push('vpcname'); + } + + return hiddenFields; + }, + fields:[ { + name: { + label: 'label.name' + }, + project: { + label: 'label.project' + } + }, + { + id: { + label: 'label.id' + }, + projectid: { + label: 'label.project.id' + }, + state: { + label: 'label.state' + }, + guestnetworkid: { + label: 'label.network.id' + }, + guestnetworkname: { + label: 'label.network.name' + }, + vpcid: { + label: 'label.vpc.id' + }, + vpcname: { + label: 'label.vpc' + }, + publicip: { + label: 'label.public.ip' + }, + guestipaddress: { + label: 'label.guest.ip' + }, + linklocalip: { + label: 'label.linklocal.ip' + }, + hostname: { + label: 'label.host' + }, + serviceofferingname: { + label: 'label.compute.offering' + }, + networkdomain: { + label: 'label.network.domain' + }, + domain: { + label: 'label.domain' + }, + account: { + label: 'label.account' + }, + created: { + label: 'label.created', + converter: cloudStack.converters.toLocalDate + }, + isredundantrouter: { + label: 'label.redundant.router', + converter: cloudStack.converters.toBooleanText + }, + redundantRouterState: { + label: 'label.redundant.state' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listRouters&id=" + args.context.routers[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jsonObj = json.listroutersresponse.router[0]; + addExtraPropertiesToRouterInstanceObject(jsonObj); + args.response.success({ + actionFilter: routerActionfilter, + data: jsonObj + }); + } + }); + } + }, + nics: { + title: 'label.nics', + multiple: true, + fields:[ { + name: { + label: 'label.name', + header: true + }, + type: { + label: 'label.type' + }, + traffictype: { + label: 'label.traffic.type' + }, + networkname: { + label: 'label.network.name' + }, + netmask: { + label: 'label.netmask' + }, + ipaddress: { + label: 'label.ip.address' + }, + id: { + label: 'label.id' + }, + networkid: { + label: 'label.network.id' + }, + isolationuri: { + label: 'label.isolation.uri' + }, + broadcasturi: { + label: 'label.broadcast.uri' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listRouters&id=" + args.context.routers[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jsonObj = json.listroutersresponse.router[0].nic; + + args.response.success({ + actionFilter: routerActionfilter, + data: $.map(jsonObj, function (nic, index) { + var name = 'NIC ' + (index + 1); + if (nic.isdefault) { + name += ' (' + _l('label.default') + ')'; + } + return $.extend(nic, { + name: name + }); + }) + }); + } + }); + } + } + } + } + } + } + }, + actions: { + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "virtualRouter"].id + "&state=Enabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "virtualRouter"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + + InternalLbVm: { + id: 'InternalLbVm', + label: 'label.internallbvm', + isMaximized: true, + type: 'detailView', + fields: { + name: { + label: 'label.name' + }, + ipaddress: { + label: 'label.ip.address' + }, + state: { + label: 'label.status', + indicator: { + 'Enabled': 'on' + } + } + }, + tabs: { + network: { + title: 'label.network', + fields:[ { + name: { + label: 'label.name' + } + }, + { + id: { + label: 'label.id' + }, + state: { + label: 'label.state' + }, + physicalnetworkid: { + label: 'label.physical.network.ID' + }, + destinationphysicalnetworkid: { + label: 'label.destination.physical.network.id' + }, + supportedServices: { + label: 'label.supported.services' + } + }], + dataProvider: function (args) { + refreshNspData("InternalLbVm"); + args.response.success({ + actionFilter: virtualRouterProviderActionFilter, + data: $.extend(nspMap[ "InternalLbVm"], { + supportedServices: nspMap[ "InternalLbVm"].servicelist.join(', ') + }) + }); + } + }, + + instances: { + title: 'label.instances', + listView: { + label: 'label.virtual.appliances', + id: 'internallbinstances', + fields: { + name: { + label: 'label.name' + }, + zonename: { + label: 'label.zone' + }, + routerType: { + label: 'label.type' + }, + state: { + converter: function (str) { + // For localization + return str; + }, + label: 'label.status', + indicator: { + 'Running': 'on', + 'Stopped': 'off', + 'Error': 'off' + } + } + }, + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + + var routers =[]; + $.ajax({ + url: createURL("listInternalLoadBalancerVMs&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + success: function (json) { + var items = json.listinternallbvmsresponse.internalloadbalancervm ? + json.listinternallbvmsresponse.internalloadbalancervm:[]; + + $(items).map(function (index, item) { + routers.push(item); + }); + + // Get project routers + $.ajax({ + url: createURL("listInternalLoadBalancerVMs&zoneid=" + selectedZoneObj.id + "&page=" + args.page + "&pagesize=" + pageSize + array1.join("") + "&projectid=-1"), + success: function (json) { + var items = json.listinternallbvmsresponse.internalloadbalancervm ? + json.listinternallbvmsresponse.internalloadbalancervm:[]; + + $(items).map(function (index, item) { + routers.push(item); + }); + args.response.success({ + actionFilter: internallbinstanceActionfilter, + data: $(routers).map(mapRouterType) + }); + } + }); + } + }); + }, + detailView: { + name: 'label.virtual.appliance.details', + actions: { + start: { + label: 'label.start.lb.vm', + messages: { + confirm: function (args) { + return 'message.confirm.start.lb.vm'; + }, + notification: function (args) { + return 'label.start.lb.vm'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('startInternalLoadBalancerVM&id=' + args.context.internallbinstances[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.startinternallbvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.internalloadbalancervm; + }, + getActionFilter: function () { + return internallbinstanceActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + stop: { + label: 'label.stop.lb.vm', + createForm: { + title: 'message.confirm.stop.lb.vm', + desc: 'label.stop.lb.vm', + fields: { + forced: { + label: 'force.stop', + isBoolean: true, + isChecked: false + } + } + }, + messages: { + notification: function (args) { + return 'label.stop.lb.vm'; + } + }, + action: function (args) { + var array1 =[]; + array1.push("&forced=" + (args.data.forced == "on")); + $.ajax({ + url: createURL('stopInternalLoadBalancerVM&id=' + args.context.internallbinstances[0].id + array1.join("")), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.stopinternallbvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.internalloadbalancervm; + }, + getActionFilter: function () { + return internallbinstanceActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + migrate: { + label: 'label.migrate.lb.vm', + createForm: { + title: 'label.migrate.lb.vm', + fields: { + hostId: { + label: 'label.host', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL("findHostsForMigration&VirtualMachineId=" + args.context.internallbinstances[0].id), + dataType: "json", + async: true, + success: function (json) { + var hostObjs = json.findhostsformigrationresponse.host; + var items =[]; + $(hostObjs).each(function () { + items.push({ + id: this.id, + description: (this.name + " (" + (this.suitableformigration ? "Suitable": "Not Suitable") + ")") + }); + }); + args.response.success({ + data: items + }); + } + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + } + } + }, + messages: { + notification: function (args) { + return 'label.migrate.lb.vm'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("migrateSystemVm&hostid=" + args.data.hostId + "&virtualmachineid=" + args.context.internallbinstances[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.migratesystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + //return json.queryasyncjobresultresponse.jobresult.systemvminstance; //not all properties returned in systemvminstance + $.ajax({ + url: createURL("listInternalLoadBalancerVMs&id=" + json.queryasyncjobresultresponse.jobresult.systemvm.id), + dataType: "json", + async: false, + success: function (json) { + var items = json.listinternallbvmsresponse.internalloadbalancervm; + if (items != null && items.length > 0) { + return items[0]; + } + } + }); + }, + getActionFilter: function () { + return internallbinstanceActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + viewConsole: { + label: 'label.view.console', + action: { + externalLink: { + url: function (args) { + return clientConsoleUrl + '?cmd=access&vm=' + args.context.internallbinstances[0].id; + }, + title: function (args) { + return args.context.internallbinstances[0].id.substr(0, 8); + //title in window.open() can't have space nor longer than 8 characters. Otherwise, IE browser will have error. + }, + width: 820, + height: 640 + } + } + } + }, + tabs: { + details: { + title: 'label.details', + preFilter: function (args) { + var hiddenFields =[]; + if (! args.context.internallbinstances[0].project) { + hiddenFields.push('project'); + hiddenFields.push('projectid'); + } + if (selectedZoneObj.networktype == 'Basic') { + hiddenFields.push('publicip'); + //In Basic zone, guest IP is public IP. So, publicip is not returned by listRouters API. Only guestipaddress is returned by listRouters API. + } + + if ('routers' in args.context && args.context.routers[0].vpcid != undefined) { + hiddenFields.push('guestnetworkid'); + hiddenFields.push('guestnetworkname'); + } else if ('routers' in args.context && args.context.routers[0].guestnetworkid != undefined) { + hiddenFields.push('vpcid'); + hiddenFields.push('vpcname'); + } + + return hiddenFields; + }, + fields:[ { + name: { + label: 'label.name' + }, + project: { + label: 'label.project' + } + }, + { + id: { + label: 'label.id' + }, + projectid: { + label: 'label.project.id' + }, + state: { + label: 'label.state' + }, + guestnetworkid: { + label: 'label.network.id' + }, + guestnetworkname: { + label: 'label.network.name' + }, + vpcid: { + label: 'label.vpc.id' + }, + vpcname: { + label: 'label.vpc' + }, + publicip: { + label: 'label.public.ip' + }, + guestipaddress: { + label: 'label.guest.ip' + }, + linklocalip: { + label: 'label.linklocal.ip' + }, + hostname: { + label: 'label.host' + }, + serviceofferingname: { + label: 'label.compute.offering' + }, + networkdomain: { + label: 'label.network.domain' + }, + domain: { + label: 'label.domain' + }, + account: { + label: 'label.account' + }, + created: { + label: 'label.created', + converter: cloudStack.converters.toLocalDate + }, + isredundantrouter: { + label: 'label.redundant.router', + converter: cloudStack.converters.toBooleanText + }, + redundantRouterState: { + label: 'label.redundant.state' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listInternalLoadBalancerVMs&id=" + args.context.internallbinstances[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jsonObj = json.listinternallbvmsresponse.internalloadbalancervm[0]; + addExtraPropertiesToRouterInstanceObject(jsonObj); + args.response.success({ + actionFilter: internallbinstanceActionfilter, + data: jsonObj + }); + } + }); + } + }, + nics: { + title: 'label.nics', + multiple: true, + fields:[ { + name: { + label: 'label.name', + header: true + }, + type: { + label: 'label.type' + }, + traffictype: { + label: 'label.traffic.type' + }, + networkname: { + label: 'label.network.name' + }, + netmask: { + label: 'label.netmask' + }, + ipaddress: { + label: 'label.ip.address' + }, + id: { + label: 'label.id' + }, + networkid: { + label: 'label.network.id' + }, + isolationuri: { + label: 'label.isolation.uri' + }, + broadcasturi: { + label: 'label.broadcast.uri' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listInternalLoadBalancerVMs&id=" + args.context.internallbinstances[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jsonObj = json.listinternallbvmsresponse.internalloadbalancervm[0].nic; + + args.response.success({ + actionFilter: internallbinstanceActionfilter, + data: $.map(jsonObj, function (nic, index) { + var name = 'NIC ' + (index + 1); + if (nic.isdefault) { + name += ' (' + _l('label.default') + ')'; + } + return $.extend(nic, { + name: name + }); + }) + }); + } + }); + } + } + } + } + } + } + }, + actions: { + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "InternalLbVm"].id + "&state=Enabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "InternalLbVm"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + + vpcVirtualRouter: { + id: 'vpcVirtualRouterProviders', + label: 'label.vpc.virtual.router', + isMaximized: true, + type: 'detailView', + fields: { + name: { + label: 'label.name' + }, + ipaddress: { + label: 'label.ip.address' + }, + state: { + label: 'label.status', + indicator: { + 'Enabled': 'on' + } + } + }, + tabs: { + network: { + title: 'label.network', + fields:[ { + name: { + label: 'label.name' + } + }, + { + id: { + label: 'label.id' + }, + state: { + label: 'label.state' + }, + physicalnetworkid: { + label: 'label.physical.network.ID' + }, + destinationphysicalnetworkid: { + label: 'label.destination.physical.network.id' + }, + supportedServices: { + label: 'label.supported.services' + } + }], + dataProvider: function (args) { + refreshNspData("VpcVirtualRouter"); + args.response.success({ + actionFilter: virtualRouterProviderActionFilter, + data: $.extend(nspMap[ "vpcVirtualRouter"], { + supportedServices: nspMap[ "vpcVirtualRouter"].servicelist.join(', ') + }) + }); + } + }, + + instances: { + title: 'label.instances', + listView: { + label: 'label.virtual.appliances', + id: 'routers', + fields: { + name: { + label: 'label.name' + }, + zonename: { + label: 'label.zone' + }, + routerType: { + label: 'label.type' + }, + state: { + converter: function (str) { + // For localization + return str; + }, + label: 'label.status', + indicator: { + 'Running': 'on', + 'Stopped': 'off', + 'Error': 'off' + } + } + }, + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + + var data2 = { + forvpc: true + }; + var routers =[]; + $.ajax({ + url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + dataType: 'json', + data: data2, + async: true, + success: function (json) { + var items = json.listroutersresponse.router; + $(items).map(function (index, item) { + routers.push(item); + }); + + /* + * In project view, the first listRotuers API(without projectid=-1) will return the same objects as the second listRouters API(with projectid=-1), + * because in project view, all API calls are appended with projectid=[projectID]. + * Therefore, we only call the second listRouters API(with projectid=-1) in non-project view. + */ + if (cloudStack.context && cloudStack.context.projects == null) { //non-project view + $.ajax({ + url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&page=" + args.page + "&pagesize=" + pageSize + array1.join("") + "&projectid=-1"), + dataType: 'json', + data: data2, + async: false, + success: function (json) { + var items = json.listroutersresponse.router; + $(items).map(function (index, item) { + routers.push(item); + }); + } + }); + } + + args.response.success({ + actionFilter: routerActionfilter, + data: $(routers).map(mapRouterType) + }); + } + }); + }, + detailView: { + name: 'label.virtual.appliance.details', + actions: { + start: { + label: 'label.action.start.router', + messages: { + confirm: function (args) { + return 'message.action.start.router'; + }, + notification: function (args) { + return 'label.action.start.router'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('startRouter&id=' + args.context.routers[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.startrouterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.router; + }, + getActionFilter: function () { + return routerActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + stop: { + label: 'label.action.stop.router', + createForm: { + title: 'label.action.stop.router', + desc: 'message.action.stop.router', + fields: { + forced: { + label: 'force.stop', + isBoolean: true, + isChecked: false + } + } + }, + messages: { + notification: function (args) { + return 'label.action.stop.router'; + } + }, + action: function (args) { + var array1 =[]; + array1.push("&forced=" + (args.data.forced == "on")); + $.ajax({ + url: createURL('stopRouter&id=' + args.context.routers[0].id + array1.join("")), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.stoprouterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.router; + }, + getActionFilter: function () { + return routerActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + restart: { + label: 'label.action.reboot.router', + messages: { + confirm: function (args) { + return 'message.action.reboot.router'; + }, + notification: function (args) { + return 'label.action.reboot.router'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('rebootRouter&id=' + args.context.routers[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.rebootrouterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.router; + }, + getActionFilter: function () { + return routerActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + 'remove': { + label: 'label.destroy.router', + messages: { + confirm: function (args) { + if (args && args.context && args.context.routers[0]) { + if (args.context.routers[0].state == 'Running') { + return dictionary['message.action.stop.router'] + ' ' + dictionary['message.confirm.destroy.router']; + } + } + return 'message.confirm.destroy.router'; + }, + notification: function (args) { + return 'label.destroy.router'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("destroyRouter&id=" + args.context.routers[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.destroyrouterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + migrate: { + label: 'label.action.migrate.router', + createForm: { + title: 'label.action.migrate.router', + desc: '', + fields: { + hostId: { + label: 'label.host', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL("findHostsForMigration&VirtualMachineId=" + args.context.routers[0].id), + dataType: "json", + async: true, + success: function (json) { + var hostObjs = json.findhostsformigrationresponse.host; + var items =[]; + $(hostObjs).each(function () { + items.push({ + id: this.id, + description: (this.name + " (" + (this.suitableformigration ? "Suitable": "Not Suitable") + ")") + }); + }); + args.response.success({ + data: items + }); + } + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + } + } + }, + messages: { + notification: function (args) { + return 'label.action.migrate.router'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("migrateSystemVm&hostid=" + args.data.hostId + "&virtualmachineid=" + args.context.routers[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.migratesystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + //return json.queryasyncjobresultresponse.jobresult.systemvminstance; //not all properties returned in systemvminstance + $.ajax({ + url: createURL("listRouters&id=" + json.queryasyncjobresultresponse.jobresult.systemvm.id), + dataType: "json", + async: false, + success: function (json) { + var items = json.listroutersresponse.router; + if (items != null && items.length > 0) { + return items[0]; + } + } + }); + }, + getActionFilter: function () { + return routerActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + diagnostics: { + label: 'label.action.run.diagnostics', + messages: { + notification: function (args) { + return 'label.action.run.diagnostics'; + }, + complete: function(args) { + var exitcode = _l('message.diagnostics.exitcode'); + exitcode = exitcode.replace('var', args.exitcode); + var stderr = _l('message.diagnostics.stderr'); + stderr = stderr.replace('var', args.stderr); + var stdout = _l('message.diagnostics.stdout'); + stdout = stdout.replace('var', args.stdout); + var msg = "
    " + exitcode + "

    " + stderr + "

    " + stdout + "
    "; + return msg; + } + }, + createForm: { + title: 'label.action.run.diagnostics', + desc: '', + fields: { + type: { + label: 'label.run.diagnostics.type', + validation: { + required: true + }, + select: function (args) { + var items = []; + items.push({ + id: "ping", + description: "Ping" + }); + items.push({ + id: "traceroute", + description: "Traceroute" + }); + items.push({ + id: "arping", + description: "Arping" + }); + args.response.success({ + data: items + }); + } + }, + destination: { + label: 'label.run.diagnostics.destination', + validation: { + required: true + } + }, + extra: { + label: 'label.run.diagnostics.extra' + } + + } + }, + action: function (args) { + $.ajax({ + url: createURL("runDiagnostics&targetid=" + args.context.systemVMs[0].id + "&ipaddress=" + args.data.destination + "&type=" + args.data.type + "¶ms=" + args.data.extra), + dataType: "json", + async: true, + success: function(json) { + var jid = json.rundiagnosticsresponse.jobid; + args.response.success({ + _custom: { + jobId : jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.diagnostics; + + }, + getActionFilter: function(){ + return systemvmActionfilter; + } + } + + }); + } + }); //end ajax + }, + notification: { + poll: pollAsyncJobResult + } + }, + + retrieveDiagnostics: { + label: 'label.action.get.diagnostics', + messages: { + notification: function (args) { + return 'label.action.get.diagnostics'; + }, + complete: function(args) { + var url = args.url; + var htmlMsg = _l('message.download.diagnostics'); + var htmlMsg2 = htmlMsg.replace(/#/, url).replace(/00000/, url); + return htmlMsg2; + } + }, + createForm: { + title: 'label.action.get.diagnostics', + desc: 'label.get.diagnostics.desc', + fields: { + files: { + label: 'label.get.diagnostics.files' + } + } + }, + action: function (args) { + $.ajax({ + url: createURL("getDiagnosticsData&targetid=" + args.context.routers[0].id + "&files=" + args.data.files), + dataType: "json", + async: true, + success: function(json) { + var jid = json.getdiagnosticsdataresponse.jobid; + args.response.success({ + _custom: { + jobId : jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.diagnostics; + + }, + getActionFilter: function(){ + return systemvmActionfilter; + } + } + + }); + } + }); //end ajax + }, + notification: { + poll: pollAsyncJobResult + } + }, + + viewConsole: { + label: 'label.view.console', + action: { + externalLink: { + url: function (args) { + return clientConsoleUrl + '?cmd=access&vm=' + args.context.routers[0].id; + }, + title: function (args) { + return args.context.routers[0].id.substr(0, 8); + //title in window.open() can't have space nor longer than 8 characters. Otherwise, IE browser will have error. + }, + width: 820, + height: 640 + } + } + } + }, + tabs: { + details: { + title: 'label.details', + preFilter: function (args) { + var hiddenFields =[]; + if (! args.context.routers[0].project) { + hiddenFields.push('project'); + hiddenFields.push('projectid'); + } + if (selectedZoneObj.networktype == 'Basic') { + hiddenFields.push('publicip'); + //In Basic zone, guest IP is public IP. So, publicip is not returned by listRouters API. Only guestipaddress is returned by listRouters API. + } + return hiddenFields; + }, + fields:[ { + name: { + label: 'label.name' + }, + project: { + label: 'label.project' + } + }, + { + id: { + label: 'label.id' + }, + projectid: { + label: 'label.project.id' + }, + state: { + label: 'label.state' + }, + publicip: { + label: 'label.public.ip' + }, + guestipaddress: { + label: 'label.guest.ip' + }, + linklocalip: { + label: 'label.linklocal.ip' + }, + hostname: { + label: 'label.host' + }, + serviceofferingname: { + label: 'label.compute.offering' + }, + networkdomain: { + label: 'label.network.domain' + }, + domain: { + label: 'label.domain' + }, + account: { + label: 'label.account' + }, + created: { + label: 'label.created', + converter: cloudStack.converters.toLocalDate + }, + isredundantrouter: { + label: 'label.redundant.router', + converter: cloudStack.converters.toBooleanText + }, + redundantRouterState: { + label: 'label.redundant.state' + }, + vpcid: { + label: 'label.vpc.id' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listRouters&id=" + args.context.routers[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jsonObj = json.listroutersresponse.router[0]; + addExtraPropertiesToRouterInstanceObject(jsonObj); + args.response.success({ + actionFilter: routerActionfilter, + data: jsonObj + }); + } + }); + } + } + } + } + } + } + }, + actions: { + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "vpcVirtualRouter"].id + "&state=Enabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "vpcVirtualRouter"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + + Ovs: { + id: "Ovs", + label: "label.ovs", + isMaximized: true, + type: 'detailView', + fields: { + name: { + label: 'label.name' + }, + state: { + label: 'label.status', + indicator: { + 'Enabled': 'on' + } + } + }, + tabs: { + network: { + title: 'label.network', + fields: [{ + name: { + label: 'label.name' + } + }, { + state: { + label: 'label.state' + }, + supportedServices: { + label: 'label.supported.services' + }, + id: { + label: 'label.id' + }, + physicalnetworkid: { + label: 'label.physical.network.ID' + } + }], + dataProvider: function(args) { + refreshNspData("Ovs"); + args.response.success({ + actionFilter: ovsProviderActionFilter, + data: $.extend(nspMap["Ovs"], { + supportedServices: nspMap["Ovs"] == undefined? "": nspMap["Ovs"].servicelist.join(', ') + }) + }); + } + } + }, + actions: { + enable: { + label: 'label.enable.provider', + action: function(args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap["Ovs"].id + "&state=Enabled"), + dataType: "json", + success: function(json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function(args) { + return 'message.confirm.enable.provider'; + }, + notification: function() { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function(args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap["Ovs"].id + "&state=Disabled"), + dataType: "json", + success: function(json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function(args) { + return 'message.confirm.disable.provider'; + }, + notification: function() { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + + // NetScaler provider detail view + netscaler: { + type: 'detailView', + id: 'netscalerProvider', + label: 'label.netScaler', + viewAll: { + label: 'label.devices', + path: '_zone.netscalerDevices' + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + state: { + label: 'label.state' + } + }], + dataProvider: function (args) { + refreshNspData("Netscaler"); + var providerObj; + $(nspHardcodingArray).each(function () { + if (this.id == "netscaler") { + providerObj = this; + return false; //break each loop + } + }); + args.response.success({ + data: providerObj, + actionFilter: networkProviderActionFilter('netscaler') + }); + } + } + }, + actions: { + add: { + label: 'label.add.netScaler.device', + createForm: { + title: 'label.add.netScaler.device', + preFilter: cloudStack.preFilter.addLoadBalancerDevice, + fields: { + ip: { + label: 'label.ip.address', + docID: 'helpNetScalerIPAddress' + }, + username: { + label: 'label.username', + docID: 'helpNetScalerUsername' + }, + password: { + label: 'label.password', + isPassword: true, + docID: 'helpNetScalerPassword' + }, + networkdevicetype: { + label: 'label.type', + docID: 'helpNetScalerType', + select: function (args) { + var items =[]; + items.push({ + id: "NetscalerMPXLoadBalancer", + description: "NetScaler MPX LoadBalancer" + }); + items.push({ + id: "NetscalerVPXLoadBalancer", + description: "NetScaler VPX LoadBalancer" + }); + items.push({ + id: "NetscalerSDXLoadBalancer", + description: "NetScaler SDX LoadBalancer" + }); + args.response.success({ + data: items + }); + } + }, + publicinterface: { + label: 'label.public.interface', + docID: 'helpNetScalerPublicInterface' + }, + privateinterface: { + label: 'label.private.interface', + docID: 'helpNetScalerPrivateInterface' + }, + + gslbprovider: { + label: 'label.gslb.service', + isBoolean: true, + isChecked: false + }, + gslbproviderpublicip: { + label: 'label.gslb.service.public.ip' + }, + gslbproviderprivateip: { + label: 'label.gslb.service.private.ip' + }, + + numretries: { + label: 'label.numretries', + defaultValue: '2', + docID: 'helpNetScalerRetries' + }, + // inline: { + // label: 'Mode', + // select: function(args) { + // var items = []; + // items.push({id: "false", description: "side by side"}); + // items.push({id: "true", description: "inline"}); + // args.response.success({data: items}); + // } + // }, + dedicated: { + label: 'label.dedicated', + isBoolean: true, + isChecked: false, + docID: 'helpNetScalerDedicated' + }, + capacity: { + label: 'label.capacity', + validation: { + required: false, + number: true + }, + docID: 'helpNetScalerCapacity' + } + } + }, + messages: { + notification: function (args) { + return 'label.add.netScaler.device'; + } + }, + action: function (args) { + if (nspMap[ "netscaler"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=Netscaler&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addNetscalerProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addNetscalerProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "netscaler"] = result.jobresult.networkserviceprovider; + addExternalLoadBalancer(args, selectedPhysicalNetworkObj, "addNetscalerLoadBalancer", "addnetscalerloadbalancerresponse", "netscalerloadbalancer"); + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=Netscaler failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=Netscaler failed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else { + addExternalLoadBalancer(args, selectedPhysicalNetworkObj, "addNetscalerLoadBalancer", "addnetscalerloadbalancerresponse", "netscalerloadbalancer"); + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "netscaler"].id + "&state=Enabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "netscaler"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + destroy: { + label: 'label.shutdown.provider', + action: function (args) { + $.ajax({ + url: createURL("deleteNetworkServiceProvider&id=" + nspMap[ "netscaler"].id), + dataType: "json", + success: function (json) { + var jid = json.deletenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + + $(window).trigger('cloudStack.fullRefresh'); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.shutdown.provider'; + }, + notification: function (args) { + return 'label.shutdown.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + + //Baremetal DHCP provider detail view + BaremetalDhcpProvider: { + type: 'detailView', + id: 'BaremetalDhcpProvider', + label: 'label.baremetal.dhcp.provider', + viewAll: { + label: 'label.devices', + path: '_zone.BaremetalDhcpDevices' + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + state: { + label: 'label.state' + } + }], + dataProvider: function (args) { + refreshNspData("BaremetalDhcpProvider"); + var providerObj; + $(nspHardcodingArray).each(function () { + if (this.id == "BaremetalDhcpProvider") { + providerObj = this; + return false; //break each loop + } + }); + args.response.success({ + data: providerObj, + actionFilter: networkProviderActionFilter('BaremetalDhcpProvider') + }); + } + } + }, + actions: { + add: { + label: 'label.add.baremetal.dhcp.device', + createForm: { + title: 'label.add.baremetal.dhcp.device', + fields: { + url: { + label: 'label.url', + validation: { + required: true + } + }, + username: { + label: 'label.username', + validation: { + required: true + } + }, + password: { + label: 'label.password', + isPassword: true, + validation: { + required: true + } + } + } + }, + action: function (args) { + addBaremetalDhcpDeviceFn(args); + }, + messages: { + notification: function (args) { + return 'label.add.baremetal.dhcp.device'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "BaremetalDhcpProvider"].id + "&state=Enabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "BaremetalDhcpProvider"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + destroy: { + label: 'label.shutdown.provider', + action: function (args) { + $.ajax({ + url: createURL("deleteNetworkServiceProvider&id=" + nspMap[ "BaremetalDhcpProvider"].id), + dataType: "json", + success: function (json) { + var jid = json.deletenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + + $(window).trigger('cloudStack.fullRefresh'); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.shutdown.provider'; + }, + notification: function (args) { + return 'label.shutdown.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + + Tungsten: { + id: 'Tungsten', + label: 'label.tungsten', + isMaximized: true, + type: 'detailView', + fields: { + name: { + label: 'label.name' + }, + ipaddress: { + label: 'label.ip.address' + }, + state: { + label: 'label.status', + indicator: { + 'Enabled': 'on' + } + } + }, + tabs: { + network: { + title: 'label.network', + fields:[ { + name: { + label: 'label.name' + } + }, + { + id: { + label: 'label.id' + }, + state: { + label: 'label.state' + }, + physicalnetworkid: { + label: 'label.physical.network.ID' + }, + destinationphysicalnetworkid: { + label: 'label.destination.physical.network.id' + }, + supportedServices: { + label: 'label.supported.services' + } + }], + dataProvider: function (args) { + refreshNspData("Tungsten"); + args.response.success({ + actionFilter: virtualRouterProviderActionFilter, + data: $.extend(nspMap[ "Tungsten"], { + supportedServices: nspMap[ "Tungsten"].servicelist.join(', ') + }) + }); + } + } + } + }, + + //Baremetal PXE provider detail view + BaremetalPxeProvider: { + type: 'detailView', + id: 'BaremetalPxeProvider', + label: 'label.baremetal.pxe.provider', + viewAll: { + label: 'label.devices', + path: '_zone.BaremetalPxeDevices' + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + state: { + label: 'label.state' + } + }], + dataProvider: function (args) { + refreshNspData("BaremetalPxeProvider"); + var providerObj; + $(nspHardcodingArray).each(function () { + if (this.id == "BaremetalPxeProvider") { + providerObj = this; + return false; //break each loop + } + }); + args.response.success({ + data: providerObj, + actionFilter: networkProviderActionFilter('BaremetalPxeProvider') + }); + } + } + }, + actions: { + add: { + label: 'label.baremetal.pxe.device', + createForm: { + title: 'label.baremetal.pxe.device', + fields: { + url: { + label: 'label.url', + validation: { + required: true + } + }, + username: { + label: 'label.username', + validation: { + required: true + } + }, + password: { + label: 'label.password', + isPassword: true, + validation: { + required: true + } + }, + tftpdir: { + label: 'label.tftp.root.directory', + validation: { + required: true + } + } + } + }, + action: function (args) { + addBaremetalPxeDeviceFn(args); + }, + messages: { + notification: function (args) { + return 'label.baremetal.pxe.device'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "BaremetalPxeProvider"].id + "&state=Enabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "BaremetalPxeProvider"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + destroy: { + label: 'label.shutdown.provider', + action: function (args) { + $.ajax({ + url: createURL("deleteNetworkServiceProvider&id=" + nspMap[ "BaremetalPxeProvider"].id), + dataType: "json", + success: function (json) { + var jid = json.deletenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + + $(window).trigger('cloudStack.fullRefresh'); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.shutdown.provider'; + }, + notification: function (args) { + return 'label.shutdown.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + + //f5 provider detail view + f5: { + type: 'detailView', + id: 'f5Provider', + label: 'label.f5', + viewAll: { + label: 'label.devices', + path: '_zone.f5Devices' + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + state: { + label: 'label.state' + } + }], + dataProvider: function (args) { + refreshNspData("F5BigIp"); + var providerObj; + $(nspHardcodingArray).each(function () { + if (this.id == "f5") { + providerObj = this; + return false; //break each loop + } + }); + args.response.success({ + data: providerObj, + actionFilter: networkProviderActionFilter('f5') + }); + } + } + }, + actions: { + add: { + label: 'label.add.F5.device', + createForm: { + title: 'label.add.F5.device', + preFilter: cloudStack.preFilter.addLoadBalancerDevice, + fields: { + ip: { + label: 'label.ip.address', + docID: 'helpF5IPAddress' + }, + username: { + label: 'label.username', + docID: 'helpF5Username' + }, + password: { + label: 'label.password', + docID: 'helpF5Password', + isPassword: true + }, + networkdevicetype: { + label: 'label.type', + docID: 'helpF5Type', + select: function (args) { + var items =[]; + items.push({ + id: "F5BigIpLoadBalancer", + description: "F5 Big Ip Load Balancer" + }); + args.response.success({ + data: items + }); + } + }, + publicinterface: { + label: 'label.public.interface', + docID: 'helpF5PublicInterface' + }, + privateinterface: { + label: 'label.private.interface', + docID: 'helpF5PrivateInterface' + }, + numretries: { + label: 'label.numretries', + docID: 'helpF5Retries', + defaultValue: '2' + }, + //Inline Mode has been moved from Add F5 Device to Create Network Offering (both backend and UI) + /* + inline: { + label: 'Mode', + docID: 'helpF5Mode', + select: function(args) { + var items = []; + items.push({id: "false", description: "side by side"}); + items.push({id: "true", description: "inline"}); + args.response.success({data: items}); + } + }, + */ + dedicated: { + label: 'label.dedicated', + docID: 'helpF5Dedicated', + isBoolean: true, + isChecked: false + }, + capacity: { + label: 'label.capacity', + docID: 'helpF5Capacity', + validation: { + required: false, + number: true + } + } + } + }, + action: function (args) { + if (nspMap[ "f5"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=F5BigIp&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addF5ProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addF5ProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "f5"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + addExternalLoadBalancer(args, selectedPhysicalNetworkObj, "addF5LoadBalancer", "addf5bigiploadbalancerresponse"); + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=F5BigIp failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=F5BigIpfailed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else { + addExternalLoadBalancer(args, selectedPhysicalNetworkObj, "addF5LoadBalancer", "addf5bigiploadbalancerresponse"); + } + }, + messages: { + notification: function (args) { + return 'label.add.F5.device'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "f5"].id + "&state=Enabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "f5"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + destroy: { + label: 'label.shutdown.provider', + action: function (args) { + $.ajax({ + url: createURL("deleteNetworkServiceProvider&id=" + nspMap[ "f5"].id), + dataType: "json", + success: function (json) { + var jid = json.deletenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + + $(window).trigger('cloudStack.fullRefresh'); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.shutdown.provider'; + }, + notification: function (args) { + return 'label.shutdown.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + + // SRX provider detailView + srx: { + type: 'detailView', + id: 'srxProvider', + label: 'label.srx', + viewAll: { + label: 'label.devices', + path: '_zone.srxDevices' + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + state: { + label: 'label.state' + } + }], + dataProvider: function (args) { + refreshNspData("JuniperSRX"); + var providerObj; + $(nspHardcodingArray).each(function () { + if (this.id == "srx") { + providerObj = this; + return false; //break each loop + } + }); + args.response.success({ + data: providerObj, + actionFilter: networkProviderActionFilter('srx') + }); + } + } + }, + actions: { + add: { + label: 'label.add.SRX.device', + createForm: { + title: 'label.add.SRX.device', + fields: { + ip: { + label: 'label.ip.address', + docID: 'helpSRXIPAddress' + }, + username: { + label: 'label.username', + docID: 'helpSRXUsername' + }, + password: { + label: 'label.password', + isPassword: true, + docID: 'helpSRXPassword' + }, + networkdevicetype: { + label: 'label.type', + docID: 'helpSRXType', + select: function (args) { + var items =[]; + items.push({ + id: "JuniperSRXFirewall", + description: "Juniper SRX Firewall" + }); + args.response.success({ + data: items + }); + } + }, + publicinterface: { + label: 'label.public.interface', + docID: 'helpSRXPublicInterface' + }, + privateinterface: { + label: 'label.private.interface', + docID: 'helpSRXPrivateInterface' + }, + usageinterface: { + label: 'label.usage.interface', + docID: 'helpSRXUsageInterface' + }, + numretries: { + label: 'label.numretries', + defaultValue: '2', + docID: 'helpSRXRetries' + }, + timeout: { + label: 'label.timeout', + defaultValue: '300', + docID: 'helpSRXTimeout' + }, + // inline: { + // label: 'Mode', + // docID: 'helpSRXMode', + // select: function(args) { + // var items = []; + // items.push({id: "false", description: "side by side"}); + // items.push({id: "true", description: "inline"}); + // args.response.success({data: items}); + // } + // }, + publicnetwork: { + label: 'label.public.network', + defaultValue: 'untrusted', + docID: 'helpSRXPublicNetwork', + isDisabled: true + }, + privatenetwork: { + label: 'label.private.network', + defaultValue: 'trusted', + docID: 'helpSRXPrivateNetwork', + isDisabled: true + }, + capacity: { + label: 'label.capacity', + validation: { + required: false, + number: true + }, + docID: 'helpSRXCapacity' + }, + dedicated: { + label: 'label.dedicated', + isBoolean: true, + isChecked: false, + docID: 'helpSRXDedicated' + } + } + }, + action: function (args) { + if (nspMap[ "srx"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=JuniperSRX&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addJuniperSRXProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addJuniperSRXProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "srx"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + addExternalFirewall(args, selectedPhysicalNetworkObj, "addSrxFirewall", "addsrxfirewallresponse", "srxfirewall"); + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=JuniperSRX failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=JuniperSRX failed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else { + addExternalFirewall(args, selectedPhysicalNetworkObj, "addSrxFirewall", "addsrxfirewallresponse", "srxfirewall"); + } + }, + messages: { + notification: function (args) { + return 'label.add.SRX.device'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "srx"].id + "&state=Enabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "srx"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + destroy: { + label: 'label.shutdown.provider', + action: function (args) { + $.ajax({ + url: createURL("deleteNetworkServiceProvider&id=" + nspMap[ "srx"].id), + dataType: "json", + success: function (json) { + var jid = json.deletenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + + $(window).trigger('cloudStack.fullRefresh'); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.shutdown.provider'; + }, + notification: function (args) { + return 'label.shutdown.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + + // Palo Alto provider detailView + pa: { + type: 'detailView', + id: 'paProvider', + label: 'label.PA', + viewAll: { + label: 'label.devices', + path: '_zone.paDevices' + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + state: { + label: 'label.state' + } + }], + dataProvider: function (args) { + refreshNspData("PaloAlto"); + var providerObj; + $(nspHardcodingArray).each(function () { + if (this.id == "pa") { + providerObj = this; + return false; //break each loop + } + }); + args.response.success({ + data: providerObj, + actionFilter: networkProviderActionFilter('pa') + }); + } + } + }, + actions: { + add: { + label: 'label.add.PA.device', + createForm: { + title: 'label.add.PA.device', + fields: { + ip: { + label: 'label.ip.address', + docID: 'helpPaloAltoIPAddress' + }, + username: { + label: 'label.username', + docID: 'helpPaloAltoUsername' + }, + password: { + label: 'label.password', + isPassword: true, + docID: 'helpPaloAltoPassword' + }, + networkdevicetype: { + label: 'label.type', + docID: 'helpPaloAltoType', + select: function (args) { + var items =[]; + items.push({ + id: "PaloAltoFirewall", + description: "Palo Alto Firewall" + }); + args.response.success({ + data: items + }); + } + }, + publicinterface: { + label: 'label.public.interface', + docID: 'helpPaloAltoPublicInterface' + }, + privateinterface: { + label: 'label.private.interface', + docID: 'helpPaloAltoPrivateInterface' + }, + //usageinterface: { + // label: 'Usage interface', + // docID: 'helpPaloAltoUsageInterface' + //}, + numretries: { + label: 'label.numretries', + defaultValue: '2', + docID: 'helpPaloAltoRetries' + }, + timeout: { + label: 'label.timeout', + defaultValue: '300', + docID: 'helpPaloAltoTimeout' + }, + // inline: { + // label: 'Mode', + // docID: 'helpPaloAltoMode', + // select: function(args) { + // var items = []; + // items.push({id: "false", description: "side by side"}); + // items.push({id: "true", description: "inline"}); + // args.response.success({data: items}); + // } + // }, + publicnetwork: { + label: 'label.public.network', + defaultValue: 'untrust', + docID: 'helpPaloAltoPublicNetwork' + }, + privatenetwork: { + label: 'label.private.network', + defaultValue: 'trust', + docID: 'helpPaloAltoPrivateNetwork' + }, + pavr: { + label: 'label.virtual.router', + docID: 'helpPaloAltoVirtualRouter' + }, + patp: { + label: 'label.PA.threat.profile', + docID: 'helpPaloAltoThreatProfile' + }, + palp: { + label: 'label.PA.log.profile', + docID: 'helpPaloAltoLogProfile' + }, + capacity: { + label: 'label.capacity', + validation: { + required: false, + number: true + }, + docID: 'helpPaloAltoCapacity' + }, + dedicated: { + label: 'label.dedicated', + isBoolean: true, + isChecked: false, + docID: 'helpPaloAltoDedicated' + } + } + }, + action: function (args) { + if (nspMap[ "pa"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=PaloAlto&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addPaloAltoProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addPaloAltoProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "pa"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + addExternalFirewall(args, selectedPhysicalNetworkObj, "addPaloAltoFirewall", "addpaloaltofirewallresponse", "pafirewall"); + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=Palo Alto failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=Palo Alto failed. Error: " + errorMsg); + } + }); + }, + 3000); + } + }); + } else { + addExternalFirewall(args, selectedPhysicalNetworkObj, "addPaloAltoFirewall", "addpaloaltofirewallresponse", "pafirewall"); + } + }, + messages: { + notification: function (args) { + return 'label.add.PA.device'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "pa"].id + "&state=Enabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "pa"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + destroy: { + label: 'label.shutdown.provider', + action: function (args) { + $.ajax({ + url: createURL("deleteNetworkServiceProvider&id=" + nspMap[ "pa"].id), + dataType: "json", + success: function (json) { + var jid = json.deletenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + + $(window).trigger('cloudStack.fullRefresh'); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.shutdown.provider'; + }, + notification: function (args) { + return 'label.shutdown.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + + // Security groups detail view + securityGroups: { + id: 'securityGroup-providers', + label: 'label.menu.security.groups', + type: 'detailView', + viewAll: { + label: 'label.rules', + path: 'network.securityGroups' + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + state: { + label: 'label.state' + } + }], + dataProvider: function (args) { + refreshNspData("SecurityGroupProvider"); + var providerObj; + $(nspHardcodingArray).each(function () { + if (this.id == "securityGroups") { + providerObj = this; + return false; //break each loop + } + }); + args.response.success({ + actionFilter: function (args) { + var allowedActions =[]; + var jsonObj = providerObj; + if (jsonObj.state == "Enabled") + allowedActions.push("disable"); else if (jsonObj.state == "Disabled") + allowedActions.push("enable"); + return allowedActions; + }, + data: providerObj + }); + } + } + }, + actions: { + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "securityGroups"].id + "&state=Enabled"), + async: true, + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "securityGroups"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + + fields: { + id: { + label: 'label.id' + }, + name: { + label: 'label.name' + } + //, + //state: { label: 'label.status' } //comment it for now, since dataProvider below doesn't get called by widget code after action is done + } + }, + // Nicira Nvp provider detail view + niciraNvp: { + type: 'detailView', + id: 'niciraNvpProvider', + label: 'label.niciraNvp', + viewAll: { + label: 'label.devices', + path: '_zone.niciraNvpDevices' + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + state: { + label: 'label.state' + } + }], + dataProvider: function (args) { + refreshNspData("NiciraNvp"); + var providerObj; + $(nspHardcodingArray).each(function () { + if (this.id == "niciraNvp") { + providerObj = this; + return false; //break each loop + } + }); + args.response.success({ + data: providerObj, + actionFilter: networkProviderActionFilter('niciraNvp') + }); + } + } + }, + actions: { + add: { + label: 'label.add.NiciraNvp.device', + createForm: { + title: 'label.add.NiciraNvp.device', + preFilter: function (args) { + }, + // TODO What is this? + fields: { + host: { + label: 'label.ip.address' + }, + username: { + label: 'label.username' + }, + password: { + label: 'label.password', + isPassword: true + }, + numretries: { + label: 'label.numretries', + defaultValue: '2' + }, + transportzoneuuid: { + label: 'label.nicira.transportzoneuuid' + }, + l3gatewayserviceuuid: { + label: 'label.nicira.l3gatewayserviceuuid' + }, + l2gatewayserviceuuid: { + label: 'label.nicira.l2gatewayserviceuuid' + } + } + }, + action: function (args) { + if (nspMap[ "niciraNvp"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=NiciraNvp&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addNiciraNvpProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addNiciraNvpProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "niciraNvp"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + addNiciraNvpDevice(args, selectedPhysicalNetworkObj, "addNiciraNvpDevice", "addniciranvpdeviceresponse", "niciranvpdevice") + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=NiciraNvp failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=NiciraNvp failed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else { + addNiciraNvpDevice(args, selectedPhysicalNetworkObj, "addNiciraNvpDevice", "addniciranvpdeviceresponse", "niciranvpdevice") + } + }, + messages: { + notification: function (args) { + return 'label.add.NiciraNvp.device'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "niciraNvp"].id + "&state=Enabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "niciraNvp"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + destroy: { + label: 'label.shutdown.provider', + action: function (args) { + $.ajax({ + url: createURL("deleteNetworkServiceProvider&id=" + nspMap[ "niciraNvp"].id), + dataType: "json", + success: function (json) { + var jid = json.deletenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + + $(window).trigger('cloudStack.fullRefresh'); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.shutdown.provider'; + }, + notification: function (args) { + return 'label.shutdown.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + // Brocade Vcs provider detail view + brocadeVcs: { + type: 'detailView', + id: 'brocadeVcsProvider', + label: 'label.brocadeVcs', + viewAll: { + label: 'label.devices', + path: '_zone.brocadeVcsDevices' + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + state: { + label: 'label.state' + } + }], + dataProvider: function (args) { + refreshNspData("BrocadeVcs"); + var providerObj; + $(nspHardcodingArray).each(function () { + if (this.id == "brocadeVcs") { + providerObj = this; + return false; //break each loop + } + }); + args.response.success({ + data: providerObj, + actionFilter: networkProviderActionFilter('brocadeVcs') + }); + } + } + }, + actions: { + add: { + label: 'label.add.BrocadeVcs.device', + createForm: { + title: 'label.add.BrocadeVcs.device', + preFilter: function (args) { + }, + // TODO What is this? + fields: { + host: { + label: 'label.ip.address' + }, + username: { + label: 'label.username' + }, + password: { + label: 'label.password', + isPassword: true + } + } + }, + action: function (args) { + if (nspMap[ "brocadeVcs"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=BrocadeVcs&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addBrocadeVcsProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addBrocadeVcsProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "brocadeVcs"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + addBrocadeVcsDevice(args, selectedPhysicalNetworkObj, "addBrocadeVcsDevice", "addbrocadevcsdeviceresponse", "brocadevcsdevice") + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=BrocadeVcs failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=BrocadeVcs failed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else { + addBrocadeVcsDevice(args, selectedPhysicalNetworkObj, "addBrocadeVcsDevice", "addbrocadevcsdeviceresponse", "brocadevcsdevice") + } + }, + messages: { + notification: function (args) { + return 'label.add.BrocadeVcs.device'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "brocadeVcs"].id + "&state=Enabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "brocadeVcs"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + destroy: { + label: 'label.shutdown.provider', + action: function (args) { + $.ajax({ + url: createURL("deleteNetworkServiceProvider&id=" + nspMap[ "brocadeVcs"].id), + dataType: "json", + success: function (json) { + var jid = json.deletenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + $(window).trigger('cloudStack.fullRefresh'); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.shutdown.provider'; + }, + notification: function (args) { + return 'label.shutdown.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + // BigSwitch BCF provider detail view + bigswitchBcf: { + type: 'detailView', + id: 'bigswitchBcfProvider', + label: 'label.bigswitchBcf', + viewAll: { + label: 'label.devices', + path: '_zone.bigswitchBcfDevices' + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + state: { + label: 'label.state' + } + }], + dataProvider: function (args) { + refreshNspData("BigSwitchBcf"); + var providerObj; + $(nspHardcodingArray).each(function () { + if (this.id == "bigswitchBcf") { + providerObj = this; + return false; + } + }); + args.response.success({ + data: providerObj, + actionFilter: networkProviderActionFilter('bigswitchBcf') + }); + } + } + }, + actions: { + add: { + label: 'label.add.BigSwitchBcf.device', + createForm: { + title: 'label.add.BigSwitchBcf.device', + preFilter: function (args) { + }, + fields: { + host: { + label: 'label.host.name' + }, + username: { + label: 'label.username' + }, + password: { + label: 'label.password', + isPassword: true + }, + nat: { + label: 'label.bigswitch.bcf.nat', + isBoolean: true, + isChecked: false + }, + numretries: { + label: 'label.numretries', + defaultValue: '2' + } + } + }, + action: function (args) { + if (nspMap[ "bigswitchBcf"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=BigSwitchBcf&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addBigSwitchBcfProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addBigSwitchBcfProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "bigswitchBcf"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + addBigSwitchBcfDevice(args, selectedPhysicalNetworkObj, "addBigSwitchBcfDevice", "addbigswitchbcfdeviceresponse", "bigswitchbcfdevice") + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=BigSwitchBcf failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=BigSwitchBcf failed. Error: " + errorMsg); + } + }); + }, + 3000); + } + }); + } else { + addBigSwitchBcfDevice(args, selectedPhysicalNetworkObj, "addBigSwitchBcfDevice", "addbigswitchbcfdeviceresponse", "bigswitchbcfdevice") + } + }, + messages: { + notification: function (args) { + return 'label.add.BigSwitchBcf.device'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "bigswitchBcf"].id + "&state=Enabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "bigswitchBcf"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + destroy: { + label: 'label.shutdown.provider', + action: function (args) { + $.ajax({ + url: createURL("deleteNetworkServiceProvider&id=" + nspMap[ "bigswitchBcf"].id), + dataType: "json", + success: function (json) { + var jid = json.deletenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + + $(window).trigger('cloudStack.fullRefresh'); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.shutdown.provider'; + }, + notification: function (args) { + return 'label.shutdown.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + + //ovs + Ovs: { + id: 'ovsProviders', + label: 'label.ovs', + isMaximized: true, + type: 'detailView', + fields: { + name: { + label: 'label.name' + }, + ipaddress: { + label: 'label.ip.address' + }, + state: { + label: 'label.status', + indicator: { + 'Enabled': 'on' + } + } + }, + tabs: { + network: { + title: 'label.network', + fields:[ { + name: { + label: 'label.name' + } + }, + { + id: { + label: 'label.id' + }, + state: { + label: 'label.state' + }, + physicalnetworkid: { + label: 'label.physical.network.ID' + }, + destinationphysicalnetworkid: { + label: 'label.destination.physical.network.id' + }, + supportedServices: { + label: 'label.supported.services' + } + }], + dataProvider: function (args) { + refreshNspData("Ovs"); + args.response.success({ + actionFilter: virtualRouterProviderActionFilter, + data: $.extend(nspMap[ "Ovs"], { + supportedServices: nspMap["Ovs"] == undefined? "": nspMap["Ovs"].servicelist.join(', ') + }) + }); + } + }, + + instances: { + title: 'label.instances', + listView: { + label: 'label.virtual.appliances', + id: 'routers', + fields: { + name: { + label: 'label.name' + }, + zonename: { + label: 'label.zone' + }, + routerType: { + label: 'label.type' + }, + state: { + converter: function (str) { + // For localization + return str; + }, + label: 'label.status', + indicator: { + 'Running': 'on', + 'Stopped': 'off', + 'Error': 'off' + } + } + }, + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + + var data2 = { + forvpc: false + }; + var routers =[]; + $.ajax({ + url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + data: data2, + success: function (json) { + var items = json.listroutersresponse.router ? + json.listroutersresponse.router:[]; + + $(items).map(function (index, item) { + routers.push(item); + }); + + // Get project routers + $.ajax({ + url: createURL("listRouters&zoneid=" + selectedZoneObj.id + "&page=" + args.page + "&pagesize=" + pageSize + array1.join("") + "&projectid=-1"), + data: data2, + success: function (json) { + var items = json.listroutersresponse.router ? + json.listroutersresponse.router:[]; + + $(items).map(function (index, item) { + routers.push(item); + }); + args.response.success({ + actionFilter: routerActionfilter, + data: $(routers).map(mapRouterType) + }); + } + }); + } + }); + }, + detailView: { + name: 'label.virtual.appliance.details', + actions: { + start: { + label: 'label.action.start.router', + messages: { + confirm: function (args) { + return 'message.action.start.router'; + }, + notification: function (args) { + return 'label.action.start.router'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('startRouter&id=' + args.context.routers[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.startrouterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.domainrouter; + }, + getActionFilter: function () { + return routerActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + stop: { + label: 'label.action.stop.router', + createForm: { + title: 'label.action.stop.router', + desc: 'message.action.stop.router', + fields: { + forced: { + label: 'force.stop', + isBoolean: true, + isChecked: false + } + } + }, + messages: { + notification: function (args) { + return 'label.action.stop.router'; + } + }, + action: function (args) { + var array1 =[]; + array1.push("&forced=" + (args.data.forced == "on")); + $.ajax({ + url: createURL('stopRouter&id=' + args.context.routers[0].id + array1.join("")), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.stoprouterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.domainrouter; + }, + getActionFilter: function () { + return routerActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + 'remove': { + label: 'label.destroy.router', + messages: { + confirm: function (args) { + if (args && args.context && args.context.routers[0]) { + if (args.context.routers[0].state == 'Running') { + return dictionary['message.action.stop.router'] + ' ' + dictionary['message.confirm.destroy.router']; + } + } + return 'message.confirm.destroy.router'; + }, + notification: function (args) { + return 'label.destroy.router'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("destroyRouter&id=" + args.context.routers[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.destroyrouterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + migrate: { + label: 'label.action.migrate.router', + createForm: { + title: 'label.action.migrate.router', + desc: '', + fields: { + hostId: { + label: 'label.host', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL("findHostsForMigration&VirtualMachineId=" + args.context.routers[0].id), + dataType: "json", + async: true, + success: function (json) { + var hostObjs = json.findhostsformigrationresponse.host; + var items =[]; + $(hostObjs).each(function () { + items.push({ + id: this.id, + description: (this.name + " (" + (this.suitableformigration ? "Suitable": "Not Suitable") + ")") + }); + }); + args.response.success({ + data: items + }); + } + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + } + } + }, + messages: { + notification: function (args) { + return 'label.action.migrate.router'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("migrateSystemVm&hostid=" + args.data.hostId + "&virtualmachineid=" + args.context.routers[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.migratesystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + //return json.queryasyncjobresultresponse.jobresult.systemvminstance; //not all properties returned in systemvminstance + $.ajax({ + url: createURL("listRouters&id=" + json.queryasyncjobresultresponse.jobresult.systemvm.id), + dataType: "json", + async: false, + success: function (json) { + var items = json.listroutersresponse.router; + if (items != null && items.length > 0) { + return items[0]; + } + } + }); + }, + getActionFilter: function () { + return routerActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + viewConsole: { + label: 'label.view.console', + action: { + externalLink: { + url: function (args) { + return clientConsoleUrl + '?cmd=access&vm=' + args.context.routers[0].id; + }, + title: function (args) { + return args.context.routers[0].id.substr(0, 8); + //title in window.open() can't have space nor longer than 8 characters. Otherwise, IE browser will have error. + }, + width: 820, + height: 640 + } + } + } + }, + tabs: { + details: { + title: 'label.details', + preFilter: function (args) { + var hiddenFields =[]; + if (! args.context.routers[0].project) { + hiddenFields.push('project'); + hiddenFields.push('projectid'); + } + if (selectedZoneObj.networktype == 'Basic') { + hiddenFields.push('publicip'); + //In Basic zone, guest IP is public IP. So, publicip is not returned by listRouters API. Only guestipaddress is returned by listRouters API. + } + + if ('routers' in args.context && args.context.routers[0].vpcid != undefined) { + hiddenFields.push('guestnetworkid'); + hiddenFields.push('guestnetworkname'); + } else if ('routers' in args.context && args.context.routers[0].guestnetworkid != undefined) { + hiddenFields.push('vpcid'); + hiddenFields.push('vpcname'); + } + + return hiddenFields; + }, + fields:[ { + name: { + label: 'label.name' + }, + project: { + label: 'label.project' + } + }, + { + id: { + label: 'label.id' + }, + projectid: { + label: 'label.project.id' + }, + state: { + label: 'label.state' + }, + guestnetworkid: { + label: 'label.network.id' + }, + guestnetworkname: { + label: 'label.network.name' + }, + vpcid: { + label: 'label.vpc.id' + }, + vpcname: { + label: 'label.vpc' + }, + publicip: { + label: 'label.public.ip' + }, + guestipaddress: { + label: 'label.guest.ip' + }, + linklocalip: { + label: 'label.linklocal.ip' + }, + hostname: { + label: 'label.host' + }, + serviceofferingname: { + label: 'label.compute.offering' + }, + networkdomain: { + label: 'label.network.domain' + }, + domain: { + label: 'label.domain' + }, + account: { + label: 'label.account' + }, + created: { + label: 'label.created', + converter: cloudStack.converters.toLocalDate + }, + isredundantrouter: { + label: 'label.redundant.router', + converter: cloudStack.converters.toBooleanText + }, + redundantRouterState: { + label: 'label.redundant.state' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listRouters&id=" + args.context.routers[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jsonObj = json.listroutersresponse.router[0]; + addExtraPropertiesToRouterInstanceObject(jsonObj); + args.response.success({ + actionFilter: routerActionfilter, + data: jsonObj + }); + } + }); + } + }, + nics: { + title: 'label.nics', + multiple: true, + fields:[ { + name: { + label: 'label.name', + header: true + }, + type: { + label: 'label.type' + }, + traffictype: { + label: 'label.traffic.type' + }, + networkname: { + label: 'label.network.name' + }, + netmask: { + label: 'label.netmask' + }, + ipaddress: { + label: 'label.ip.address' + }, + id: { + label: 'label.id' + }, + networkid: { + label: 'label.network.id' + }, + isolationuri: { + label: 'label.isolation.uri' + }, + broadcasturi: { + label: 'label.broadcast.uri' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listRouters&id=" + args.context.routers[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jsonObj = json.listroutersresponse.router[0].nic; + + args.response.success({ + actionFilter: routerActionfilter, + data: $.map(jsonObj, function (nic, index) { + var name = 'NIC ' + (index + 1); + if (nic.isdefault) { + name += ' (' + _l('label.default') + ')'; + } + return $.extend(nic, { + name: name + }); + }) + }); + } + }); + } + } + } + } + } + } + }, + actions: { + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "Ovs"].id + "&state=Enabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "Ovs"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + + Opendaylight: { + type: 'detailView', + id: 'openDaylightProvider', + label: 'label.openDaylight', + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + state: { + label: 'label.state' + } + }], + dataProvider: function (args) { + refreshNspData("Opendaylight"); + var providerObj; + $(nspHardcodingArray).each(function () { + if (this.id == "Opendaylight") { + providerObj = this; + return false; //break each loop + } + }); + args.response.success({ + data: providerObj, + actionFilter: networkProviderActionFilter('Opendaylight') + }); + } + }, + controllers: { + title: 'label.opendaylight.controllers', + listView: { + id: 'openDaylightControllerList', + fields: { + name: { + label: 'label.name' + }, + url: { + label: 'label.url' + }, + username: { + label: 'label.username' + } + }, + dataProvider: function (args) { + var providerObj + $.ajax({ + url: createURL("listOpenDaylightControllers"), + async: false, + success: function (json) { + providerObj = json.listOpenDaylightControllers.opendaylightcontroller + } + }); + args.response.success({ + data: providerObj + }); + }, + detailView: { + name: "OpenDaylight Controller", + tabs: { + details: { + title: 'label.opendaylight.controllerdetail', + fields:[ { + name: { + label: 'label.name' + }, + url: { + label: 'label.url', header: true + }, + username: { + label: 'label.username' + } + }], + dataProvider: function (args) { + var providerObj + $.ajax({ + url: createURL("listOpenDaylightControllers&id=" + args.id), + async: false, + success: function (json) { + providerObj = json.listOpenDaylightControllers.opendaylightcontroller + } + }); + args.response.success({ + data: providerObj[0], + actionFilter: function(args) { return [ 'destroy' ] } + }); + } + } + }, + actions: { + destroy: { + label: 'label.delete.OpenDaylight.device', + action: function (args) { + $.ajax({ + url: createURL("deleteOpenDaylightController&id=" + args.data.id), + dataType: "json", + success: function (json) { + var jid = json.deleteOpenDaylightController.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + notification: function(args) { + return 'label.openaylight.destroycontroller' + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + } + } + } + }, + actions: { + add: { + label: 'label.add.OpenDaylight.device', + createForm: { + title: 'label.add.OpenDaylight.device', + preFilter: function (args) { + }, + // TODO What is this? + fields: { + url: { + label: 'label.url' + }, + username: { + label: 'label.username' + }, + password: { + label: 'label.password', + isPassword: true + }, + numretries: { + label: 'label.numretries', + defaultValue: '2' + } + } + }, + action: function (args) { + if (nspMap[ "Opendaylight"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=Opendaylight&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addOpenDaylightProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addOpenDaylightProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "Opendaylight"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + addOpenDaylightController(args, selectedPhysicalNetworkObj, "addOpenDaylightController", "addopendaylightcontrollerresponse", "opendaylightcontroller") + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=OpenDaylight failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=OpenDaylight failed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else { + addOpenDaylightController(args, selectedPhysicalNetworkObj, "addOpenDaylightController", "addOpenDaylightController", "opendaylightcontroller") + } + }, + messages: { + notification: function (args) { + return 'label.add.OpenDaylight.device'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "Opendaylight"].id + "&state=Enabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "Opendaylight"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + destroy: { + label: 'label.shutdown.provider', + action: function (args) { + $.ajax({ + url: createURL("deleteNetworkServiceProvider&id=" + nspMap[ "Opendaylight"].id), + dataType: "json", + success: function (json) { + var jid = json.deletenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + + $(window).trigger('cloudStack.fullRefresh'); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.shutdown.provider'; + }, + notification: function (args) { + return 'label.shutdown.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + + // GloboDns provider detail view + GloboDns: { + isMaximized: true, + type: 'detailView', + id: 'globoDnsProvider', + label: 'label.globo.dns', + tabs: { + details: { + title: 'label.details', + fields: [{ + name: { + label: 'label.name' + } + }, { + state: { + label: 'label.state' + } + }], + dataProvider: function(args) { + refreshNspData("GloboDns"); + var providerObj; + $(nspHardcodingArray).each(function() { + if (this.id == "GloboDns") { + providerObj = this; + return false; //break each loop + } + }); + args.response.success({ + data: providerObj, + actionFilter: networkProviderActionFilter('GloboDns') + }); + } + } + }, + actions: { + add: { + label: 'label.globo.dns.configuration', + createForm: { + title: 'label.globo.dns.configuration', + preFilter: function(args) {}, + fields: { + username: { + label: 'label.username', + validation: { + required: true + } + }, + password: { + label: 'label.password', + isPassword: true, + validation: { + required: true + } + }, + url: { + label: 'label.url', + validation: { + required: true + } + } + } + }, + action: function(args) { + if (nspMap["GloboDns"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=GloboDns&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function(json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addGloboDnsProviderIntervalID = setInterval(function() { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function(json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addGloboDnsProviderIntervalID); + if (result.jobstatus == 1) { + nspMap["GloboDns"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + addGloboDnsHost(args, selectedPhysicalNetworkObj, "addGloboDnsHost", "addglobodnshostresponse"); + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=GloboDns failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=GloboDns failed. Error: " + errorMsg); + } + }); + }, g_queryAsyncJobResultInterval); + } + }); + } else { + addGloboDnsHost(args, selectedPhysicalNetworkObj, "addGloboDnsHost", "addglobodnshostresponse"); + } + }, + messages: { + notification: function(args) { + return 'label.add.globo.dns'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + enable: { + label: 'label.enable.provider', + action: function(args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap["GloboDns"].id + "&state=Enabled"), + dataType: "json", + success: function(json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function(args) { + return 'message.confirm.enable.provider'; + }, + notification: function() { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function(args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap["GloboDns"].id + "&state=Disabled"), + dataType: "json", + success: function(json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function(args) { + return 'message.confirm.disable.provider'; + }, + notification: function() { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + destroy: { + label: 'label.shutdown.provider', + action: function(args) { + $.ajax({ + url: createURL("deleteNetworkServiceProvider&id=" + nspMap["GloboDns"].id), + dataType: "json", + success: function(json) { + var jid = json.deletenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + + $(window).trigger('cloudStack.fullRefresh'); + } + }); + }, + messages: { + confirm: function(args) { + return 'message.confirm.shutdown.provider'; + }, + notification: function(args) { + return 'label.shutdown.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + }, + + ConfigDrive: { + id: "ConfigDrive", + label: "ConfigDrive", + isMaximized: true, + type: 'detailView', + fields: { + name: { + label: 'label.name' + }, + state: { + label: 'label.status', + indicator: { + 'Enabled': 'on' + } + } + }, + tabs: { + network: { + title: 'label.network', + fields: [{ + name: { + label: 'label.name' + } + }, { + state: { + label: 'label.state' + }, + supportedServices: { + label: 'label.supported.services' + }, + id: { + label: 'label.id' + }, + physicalnetworkid: { + label: 'label.physical.network.ID' + } + }], + dataProvider: function(args) { + refreshNspData("ConfigDrive"); + args.response.success({ + actionFilter: ovsProviderActionFilter, + data: $.extend(nspMap["ConfigDrive"], { + supportedServices: nspMap["ConfigDrive"] == undefined? "": nspMap["ConfigDrive"].servicelist.join(', ') + }) + }); + } + } + }, + actions: { + enable: { + label: 'label.enable.provider', + action: function(args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap["ConfigDrive"].id + "&state=Enabled"), + dataType: "json", + success: function(json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function(args) { + return 'message.confirm.enable.provider'; + }, + notification: function() { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function(args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap["ConfigDrive"].id + "&state=Disabled"), + dataType: "json", + success: function(json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function(args) { + return 'message.confirm.disable.provider'; + }, + notification: function() { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + } + } + } + } + }, + physicalResourceSection: { + sections: { + physicalResources: { + type: 'select', + title: 'label.menu.physical.resources', + listView: { + zones: { + id: 'physicalResources', + label: 'label.menu.physical.resources', + multiSelect: true, + fields: { + name: { + label: 'label.zone' + }, + networktype: { + label: 'label.network.type' + }, + domainid: { + label: 'label.public', + converter: function (args) { + if (args == null) + return "Yes"; else + return "No"; + } + }, + allocationstate: { + label: 'label.allocation.state', + converter: function (str) { + // For localization + return str; + }, + indicator: { + 'Enabled': 'on', + 'Disabled': 'off' + } + } + }, + + reorder: cloudStack.api.actions.sort('updateZone', 'physicalResources'), + + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + $.ajax({ + url: createURL("listZones&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + dataType: "json", + async: true, + success: function (json) { + zoneObjs = json.listzonesresponse.zone; + args.response.success({ + actionFilter: zoneActionfilter, + data: zoneObjs + }); + } + }); + }, + + actions: { + add: { + label: 'label.add.zone', + action: { + custom: cloudStack.uiCustom.zoneWizard( + cloudStack.zoneWizard) + }, + messages: { + notification: function (args) { + return 'label.add.zone'; + } + }, + notification: { + poll: function (args) { + args.complete({ + actionFilter: zoneActionfilter, + data: args._custom.zone + }); + } + } + }, + viewMetrics: { + label: 'label.metrics', + isHeader: true, + addRow: false, + action: { + custom: cloudStack.uiCustom.metricsView({resource: 'zones'}) + }, + messages: { + notification: function (args) { + return 'label.metrics'; + } + } + }, + startRollingMaintenance: rollingMaintenanceAction({ listView: true, entity: 'zones' }) + }, + + detailView: { + isMaximized: true, + actions: { + + startRollingMaintenance: { + label: 'label.start.rolling.maintenance', + textLabel: 'label.start.rolling.maintenance', + messages: { + notification: function (args) { + return 'label.start.rolling.maintenance'; + } + }, + createForm: { + title: 'label.start.rolling.maintenance', + fields: { + timeout: { + label: 'label.timeout', + }, + force: { + isBoolean: true, + label: 'label.start.rolling.maintenance.force' + }, + payload: { + label: 'label.start.rolling.maintenance.payload' + } + } + }, + action: function (args) { + var data = { + zoneids: args.context.physicalResources[0].id, + force: args.data.force, + timeout: args.data.timeout, + payload: args.data.payload + }; + $.ajax({ + url: createURL("startRollingMaintenance"), + dataType: "json", + data: data, + async: true, + success: function (json) { + var item = json.rollingmaintenance; + args.response.success({ + actionFilter: zoneActionfilter, + data: item + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + addVmwareDc: { + label: 'label.add.vmware.datacenter', + textLabel: 'label.add.vmware.datacenter', + messages: { + notification: function (args) { + return 'label.add.vmware.datacenter'; + } + }, + createForm: { + title: 'label.add.vmware.datacenter', + fields: { + name: { + label: 'label.dc.name', + validation: { + required: true + } + }, + vcenter: { + label: 'label.vcenter', + validation: { + required: true + } + }, + username: { + label: 'label.username', + validation: { + required: true + } + }, + password: { + label: 'label.password', + isPassword: true, + validation: { + required: true + } + } + } + }, + action: function (args) { + var data = { + zoneid: args.context.physicalResources[0].id, + name: args.data.name, + vcenter: args.data.vcenter + }; + + if (args.data.username != null && args.data.username.length > 0) { + $.extend(data, { + username: args.data.username + }) + } + if (args.data.password != null && args.data.password.length > 0) { + $.extend(data, { + password: args.data.password + }) + } + + $.ajax({ + url: createURL('addVmwareDc'), + data: data, + type: "POST", + success: function (json) { + //var item = json.addvmwaredcresponse.vmwaredc; + args.response.success(); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + updateVmwareDc: { + label: 'label.update.vmware.datacenter', + messages: { + confirm: function (args) { + return 'label.update.vmware.datacenter'; + }, + notification: function (args) { + return 'label.update.vmware.datacenter'; + } + }, + createForm: { + title: 'label.update.vmware.datacenter', + fields: { + name: { + label: 'label.vmware.datacenter.name' + }, + vcenter: { + label: 'label.vmware.datacenter.vcenter' + }, + username: { + label: 'label.username' + }, + password: { + label: 'label.password', + isPassword: true + } + } + }, + action: function (args) { + var data = args.data; + data.zoneid = args.context.physicalResources[0].id; + $.ajax({ + url: createURL('updateVmwareDc'), + data: data, + success: function (json) { + args.response.success({ + data: args.context.physicalResources[0] + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + removeVmwareDc: { + label: 'label.remove.vmware.datacenter', + messages: { + confirm: function (args) { + return 'message.confirm.remove.vmware.datacenter'; + }, + notification: function (args) { + return 'label.remove.vmware.datacenter'; + } + }, + action: function (args) { + var data = { + zoneid: args.context.physicalResources[0].id + }; + $.ajax({ + url: createURL('removeVmwareDc'), + data: data, + success: function (json) { + delete args.context.physicalResources[0].vmwaredcName; + delete args.context.physicalResources[0].vmwaredcVcenter; + delete args.context.physicalResources[0].vmwaredcId; + + selectedZoneObj = args.context.physicalResources[0]; + + args.response.success({ + data: args.context.physicalResources[0] + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + enable: { + label: 'label.action.enable.zone', + messages: { + confirm: function (args) { + return 'message.action.enable.zone'; + }, + notification: function (args) { + return 'label.action.enable.zone'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("updateZone&id=" + args.context.physicalResources[0].id + "&allocationstate=Enabled"), //embedded objects in listView is called physicalResources while embedded objects in detailView is called zones + dataType: "json", + async: true, + success: function (json) { + var item = json.updatezoneresponse.zone; + args.response.success({ + actionFilter: zoneActionfilter, + data: item + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + disable: { + label: 'label.action.disable.zone', + messages: { + confirm: function (args) { + return 'message.action.disable.zone'; + }, + notification: function (args) { + return 'label.action.disable.zone'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("updateZone&id=" + args.context.physicalResources[0].id + "&allocationstate=Disabled"), //embedded objects in listView is called physicalResources while embedded objects in detailView is called zones + dataType: "json", + async: true, + success: function (json) { + var item = json.updatezoneresponse.zone; + args.response.success({ + actionFilter: zoneActionfilter, + data: item + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + dedicateZone: { + label: 'label.dedicate.zone', + messages: { + confirm: function (args) { + return 'message.confirm.dedicate.zone'; + }, + notification: function (args) { + return 'label.zone.dedicated'; + } + }, + createForm: { + title: 'label.dedicate.zone', + fields: { + domainId: { + label: 'label.domain', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function (json) { + var domainObjs = json.listdomainsresponse.domain; + var items =[]; + + $(domainObjs).each(function () { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + + args.response.success({ + data: items + }); + } + }); + } + }, + accountId: { + label: 'label.account', + docID: 'helpAccountForDedication', + validation: { + required: false + } + } + } + }, + action: function (args) { + //EXPLICIT DEDICATION + var array2 =[]; + if (args.data.accountId != "") + array2.push("&account=" + encodeURIComponent(args.data.accountId)); + + $.ajax({ + url: createURL("dedicateZone&zoneId=" + + args.context.physicalResources[0].id + + "&domainId=" + args.data.domainId + array2.join("")), + dataType: "json", + success: function (json) { + var jid = json.dedicatezoneresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return zoneActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + releaseDedicatedZone: { + label: 'label.release.dedicated.zone', + messages: { + confirm: function (args) { + return 'message.confirm.release.dedicated.zone'; + }, + notification: function (args) { + return 'message.dedicated.zone.released'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("releaseDedicatedZone&zoneid=" + + args.context.physicalResources[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.releasededicatedzoneresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return zoneActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + 'remove': { + label: 'label.action.delete.zone', + messages: { + confirm: function (args) { + return 'message.action.delete.zone'; + }, + notification: function (args) { + return 'label.action.delete.zone'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("deleteZone&id=" + args.context.physicalResources[0].id), //embedded objects in listView is called physicalResources while embedded objects in detailView is called zones + dataType: "json", + async: true, + success: function (json) { + args.response.success({ + data: { + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + edit: { + label: 'label.edit', + action: function (args) { + var array1 =[]; + array1.push("&name=" + encodeURIComponent(args.data.name)); + array1.push("&dns1=" + encodeURIComponent(args.data.dns1)); + array1.push("&dns2=" + encodeURIComponent(args.data.dns2)); + //dns2 can be empty ("") when passed to API, so a user gets to update this field from an existing value to blank. + array1.push("&ip6dns1=" + encodeURIComponent(args.data.ip6dns1)); + //p6dns1 can be empty ("") when passed to API, so a user gets to update this field from an existing value to blank. + array1.push("&ip6dns2=" + encodeURIComponent(args.data.ip6dns2)); + //ip6dns2 can be empty ("") when passed to API, so a user gets to update this field from an existing value to blank. + + if (selectedZoneObj.networktype == "Advanced" && args.data.guestcidraddress) { + array1.push("&guestcidraddress=" + encodeURIComponent(args.data.guestcidraddress)); + } + + array1.push("&internaldns1=" + encodeURIComponent(args.data.internaldns1)); + array1.push("&internaldns2=" + encodeURIComponent(args.data.internaldns2)); + //internaldns2 can be empty ("") when passed to API, so a user gets to update this field from an existing value to blank. + array1.push("&domain=" + encodeURIComponent(args.data.domain)); + array1.push("&localstorageenabled=" + (args.data.localstorageenabled == 'on')); + $.ajax({ + url: createURL("updateZone&id=" + args.context.physicalResources[0].id + array1.join("")), + dataType: "json", + async: false, + success: function (json) { + selectedZoneObj = json.updatezoneresponse.zone; //override selectedZoneObj after update zone + args.response.success({ + data: selectedZoneObj + }); + }, + error: function (json) { + args.response.error('Could not edit zone information; please ensure all fields are valid.'); + } + }); + } + }, + enableOutOfBandManagement: { + label: 'label.outofbandmanagement.enable', + action: function (args) { + var data = { + zoneid: args.context.physicalResources[0].id + }; + $.ajax({ + url: createURL("enableOutOfBandManagementForZone"), + data: data, + success: function (json) { + var jid = json.enableoutofbandmanagementforzoneresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return zoneActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.enable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.enable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disableOutOfBandManagement: { + label: 'label.outofbandmanagement.disable', + action: function (args) { + var data = { + zoneid: args.context.physicalResources[0].id + }; + $.ajax({ + url: createURL("disableOutOfBandManagementForZone"), + data: data, + success: function (json) { + var jid = json.disableoutofbandmanagementforzoneresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return zoneActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.disable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.disable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + enableHA: { + label: 'label.ha.enable', + action: function (args) { + var data = { + zoneid: args.context.physicalResources[0].id + }; + $.ajax({ + url: createURL("enableHAForZone"), + data: data, + success: function (json) { + var jid = json.enablehaforzoneresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return zoneActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + messages: { + confirm: function (args) { + return 'label.ha.enable'; + }, + notification: function (args) { + return 'label.ha.enable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disableHA: { + label: 'label.ha.disable', + action: function (args) { + var data = { + zoneid: args.context.physicalResources[0].id + }; + $.ajax({ + url: createURL("disableHAForZone"), + data: data, + success: function (json) { + var jid = json.disablehaforzoneresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return zoneActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + messages: { + confirm: function (args) { + return 'label.ha.disable'; + }, + notification: function (args) { + return 'label.ha.disable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.details', + + preFilter: function (args) { + var hiddenFields =[]; + if (selectedZoneObj.networktype == "Basic") + hiddenFields.push("guestcidraddress"); + return hiddenFields; + }, + + fields:[ { + name: { + label: 'label.zone', + isEditable: true, + validation: { + required: true + } + } + }, + { + id: { + label: 'label.id' + }, + allocationstate: { + label: 'label.allocation.state' + }, + dns1: { + label: 'label.dns.1', + isEditable: true, + validation: { + required: true + } + }, + dns2: { + label: 'label.dns.2', + isEditable: true + }, + ip6dns1: { + label: 'label.ipv6.dns1', + isEditable: true + }, + ip6dns2: { + label: 'label.ipv6.dns2', + isEditable: true + }, + internaldns1: { + label: 'label.internal.dns.1', + isEditable: true, + validation: { + required: true + } + }, + internaldns2: { + label: 'label.internal.dns.2', + isEditable: true + }, + domainname: { + label: 'label.domain' + }, + networktype: { + label: 'label.network.type' + }, + guestcidraddress: { + label: 'label.guest.cidr', + isEditable: true + }, + domain: { + label: 'label.network.domain', + isEditable: true + }, + localstorageenabled: { + label: 'label.local.storage.enabled', + isBoolean: true, + isEditable: true, + converter: cloudStack.converters.toBooleanText + } + }, + { + isdedicated: { + label: 'label.dedicated' + }, + domainid: { + label: 'label.domain.id' + } + }, + { + vmwaredcName: { + label: 'label.vmware.datacenter.name' + }, + vmwaredcVcenter: { + label: 'label.vmware.datacenter.vcenter' + }, + vmwaredcId: { + label: 'label.vmware.datacenter.id' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL('listZones'), + data: { + id: args.context.physicalResources[0].id + }, + success: function (json) { + selectedZoneObj = json.listzonesresponse.zone[0]; + + $(window).trigger('cloudStack.module.sharedFunctions.addExtraProperties', { + obj: selectedZoneObj, + objType: "Zone" + }); + + $.ajax({ + url: createURL('listDedicatedZones'), + data: { + zoneid: args.context.physicalResources[0].id + }, + async: false, + success: function (json) { + if (json.listdedicatedzonesresponse.dedicatedzone != undefined) { + var dedicatedzoneObj = json.listdedicatedzonesresponse.dedicatedzone[0]; + if (dedicatedzoneObj.domainid != null) { + $.extend(selectedZoneObj, { + isdedicated: 'Yes', + domainid: dedicatedzoneObj.domainid, + accountid: dedicatedzoneObj.accountid + }); + } + } else { + $.extend(selectedZoneObj, { + isdedicated: 'No', + domainid: null, + accountid: null + }) + } + } + }); + + $.ajax({ + url: createURL('listApis'), //listVmwareDcs API only exists in non-oss bild, so have to check whether it exists before calling it. + data: { + name: 'listVmwareDcs' + }, + async: false, + success: function (json) { + $.ajax({ + url: createURL('listVmwareDcs'), + data: { + zoneid: args.context.physicalResources[0].id + }, + async: false, + success: function (json) { + //e.g. json == { "listvmwaredcsresponse" { "count":1 ,"VMwareDC" [ {"id":"c3c2562d-65e9-4fc7-92e2-773c2efe8f37","zoneid":1,"name":"datacenter","vcenter":"10.10.20.20"} ] } } + var vmwaredcs = json.listvmwaredcsresponse.VMwareDC; + if (vmwaredcs != null) { + selectedZoneObj.vmwaredcName = vmwaredcs[0].name; + selectedZoneObj.vmwaredcVcenter = vmwaredcs[0].vcenter; + selectedZoneObj.vmwaredcId = vmwaredcs[0].id; + } + } + }); + }, + error: function (XMLHttpResponse) { + } + //override default error handling: cloudStack.dialog.notice({ message: parseXMLHttpResponse(XMLHttpResponse)}); + }); + + args.response.success({ + actionFilter: zoneActionfilter, + data: selectedZoneObj + }); + } + }); + } + }, + + compute: { + title: 'label.compute.and.storage', + custom: cloudStack.uiCustom.systemChart('compute') + }, + network: { + title: 'label.physical.network', + custom: cloudStack.uiCustom.systemChart('network') + }, + resources: { + title: 'label.resources', + custom: cloudStack.uiCustom.systemChart('resources') + }, + + systemVMs: { + title: 'label.system.vms', + listView: { + label: 'label.system.vms', + id: 'systemVMs', + fields: { + name: { + label: 'label.name' + }, + systemvmtype: { + label: 'label.type', + converter: function (args) { + if (args == "consoleproxy") + return "Console Proxy VM"; else if (args == "secondarystoragevm") + return "Secondary Storage VM"; else + return args; + } + }, + zonename: { + label: 'label.zone' + }, + state: { + label: 'label.status', + converter: function (str) { + // For localization + return str; + }, + indicator: { + 'Running': 'on', + 'Stopped': 'off', + 'Error': 'off', + 'Destroyed': 'off' + } + } + }, + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + + var selectedZoneObj = args.context.physicalResources[0]; + $.ajax({ + url: createURL("listSystemVms&zoneid=" + selectedZoneObj.id + "&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + dataType: "json", + async: true, + success: function (json) { + var items = json.listsystemvmsresponse.systemvm; + args.response.success({ + actionFilter: systemvmActionfilter, + data: items + }); + } + }); + }, + + detailView: { + noCompact: true, + name: 'label.system.vm.details', + actions: { + start: { + label: 'label.action.start.systemvm', + messages: { + confirm: function (args) { + return 'message.action.start.systemvm'; + }, + notification: function (args) { + return 'label.action.start.systemvm'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('startSystemVm&id=' + args.context.systemVMs[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.startsystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.systemvm; + }, + getActionFilter: function () { + return systemvmActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + stop: { + label: 'label.action.stop.systemvm', + messages: { + confirm: function (args) { + return 'message.action.stop.systemvm'; + }, + notification: function (args) { + return 'label.action.stop.systemvm'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('stopSystemVm&id=' + args.context.systemVMs[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.stopsystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.systemvm; + }, + getActionFilter: function () { + return systemvmActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + restart: { + label: 'label.action.reboot.systemvm', + messages: { + confirm: function (args) { + return 'message.action.reboot.systemvm'; + }, + notification: function (args) { + return 'label.action.reboot.systemvm'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('rebootSystemVm&id=' + args.context.systemVMs[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.rebootsystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.systemvm; + }, + getActionFilter: function () { + return systemvmActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + remove: { + label: 'label.action.destroy.systemvm', + messages: { + confirm: function (args) { + return 'message.action.destroy.systemvm'; + }, + notification: function (args) { + return 'label.action.destroy.systemvm'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('destroySystemVm&id=' + args.context.systemVMs[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.destroysystemvmresponse.jobid; + args.response.success({ + _custom: { + getUpdatedItem: function () { + return { + state: 'Destroyed' + }; + }, + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + migrate: { + label: 'label.action.migrate.systemvm', + messages: { + notification: function (args) { + return 'label.action.migrate.systemvm'; + } + }, + createForm: { + title: 'label.action.migrate.systemvm', + desc: '', + fields: { + hostId: { + label: 'label.host', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL("findHostsForMigration&VirtualMachineId=" + args.context.systemVMs[0].id), + dataType: "json", + async: true, + success: function (json) { + var hostObjs = json.findhostsformigrationresponse.host; + var items =[]; + $(hostObjs).each(function () { + if (this.requiresStorageMotion == false) { + items.push({ + id: this.id, + description: (this.name + " (" + (this.suitableformigration ? "Suitable": "Not Suitable") + ")") + }); + } + }); + args.response.success({ + data: items + }); + } + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + } + } + }, + action: function (args) { + $.ajax({ + url: createURL("migrateSystemVm&hostid=" + args.data.hostId + "&virtualmachineid=" + args.context.systemVMs[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.migratesystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + //return json.queryasyncjobresultresponse.jobresult.systemvminstance; //not all properties returned in systemvminstance + $.ajax({ + url: createURL("listSystemVms&id=" + json.queryasyncjobresultresponse.jobresult.systemvm.id), + dataType: "json", + async: false, + success: function (json) { + var items = json.listsystemvmsresponse.systemvm; + if (items != null && items.length > 0) { + return items[0]; + } + } + }); + }, + getActionFilter: function () { + return systemvmActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + diagnostics: { + label: 'label.action.run.diagnostics', + messages: { + notification: function (args) { + return 'label.action.run.diagnostics'; + }, + complete: function(args) { + var exitcode = _l('message.diagnostics.exitcode'); + exitcode = exitcode.replace('var', args.exitcode); + var stderr = _l('message.diagnostics.stderr'); + stderr = stderr.replace('var', args.stderr); + var stdout = _l('message.diagnostics.stdout'); + stdout = stdout.replace('var', args.stdout); + var msg = "
    " + exitcode + "

    " + stderr + "

    " + stdout + "
    "; + return msg; + } + }, + createForm: { + title: 'label.action.run.diagnostics', + desc: '', + fields: { + type: { + label: 'label.run.diagnostics.type', + validation: { + required: true + }, + select: function (args) { + var items = []; + items.push({ + id: "ping", + description: "Ping" + }); + items.push({ + id: "traceroute", + description: "Traceroute" + }); + items.push({ + id: "arping", + description: "Arping" + }); + args.response.success({ + data: items + }); + } + }, + destination: { + label: 'label.run.diagnostics.destination', + validation: { + required: true + } + }, + extra: { + label: 'label.run.diagnostics.extra' + } + + } + }, + action: function (args) { + $.ajax({ + url: createURL("runDiagnostics&targetid=" + args.context.systemVMs[0].id + "&ipaddress=" + args.data.destination + "&type=" + args.data.type + "¶ms=" + args.data.extra), + dataType: "json", + async: true, + success: function(json) { + var jid = json.rundiagnosticsresponse.jobid; + args.response.success({ + _custom: { + jobId : jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.diagnostics; + + }, + getActionFilter: function(){ + return systemvmActionfilter; + } + } + + }); + } + }); //end ajax + }, + notification: { + poll: pollAsyncJobResult + } + }, + + retrieveDiagnostics: { + label: 'label.action.get.diagnostics', + messages: { + notification: function (args) { + return 'label.action.get.diagnostics'; + }, + complete: function(args) { + var url = args.url; + var htmlMsg = _l('message.download.diagnostics'); + var htmlMsg2 = htmlMsg.replace(/#/, url).replace(/00000/, url); + return htmlMsg2; + } + }, + createForm: { + title: 'label.action.get.diagnostics', + desc: '', + fields: { + files: { + label: 'label.get.diagnostics.files' + } + } + }, + action: function (args) { + $.ajax({ + url: createURL("getDiagnosticsData&targetid=" + args.context.systemVMs[0].id + "&files=" + args.data.files), + dataType: "json", + async: true, + success: function(json) { + var jid = json.getdiagnosticsdataresponse.jobid; + args.response.success({ + _custom: { + jobId : jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.diagnostics; + + }, + getActionFilter: function(){ + return systemvmActionfilter; + } + } + + }); + } + }); //end ajax + }, + notification: { + poll: pollAsyncJobResult + } + }, + + scaleUp: { + label: 'label.change.service.offering', + createForm: { + title: 'label.change.service.offering', + desc: function (args) { + var description = ''; + var vmObj = args.jsonObj; + //if (vmObj.state == 'Running' && vmObj.hypervisor == 'VMware') { //needs to wait for API fix that will return hypervisor property + if (vmObj.state == 'Running') { + description = 'message.read.admin.guide.scaling.up'; + } + return description; + }, + fields: { + serviceOfferingId: { + label: 'label.compute.offering', + select: function (args) { + var apiCmd = "listServiceOfferings&issystem=true"; + if (args.context.systemVMs[0].systemvmtype == "secondarystoragevm") + apiCmd += "&systemvmtype=secondarystoragevm"; else if (args.context.systemVMs[0].systemvmtype == "consoleproxy") + apiCmd += "&systemvmtype=consoleproxy"; + $.ajax({ + url: createURL(apiCmd), + dataType: "json", + async: true, + success: function (json) { + var serviceofferings = json.listserviceofferingsresponse.serviceoffering; + var items =[]; + $(serviceofferings).each(function () { + if (this.id != args.context.systemVMs[0].serviceofferingid) { + items.push({ + id: this.id, + description: this.name + }); + } + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + + action: function (args) { + $.ajax({ + url: createURL("scaleSystemVm&id=" + args.context.systemVMs[0].id + "&serviceofferingid=" + args.data.serviceOfferingId), + dataType: "json", + async: true, + success: function (json) { + var jid = json.changeserviceforsystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.systemvm; + }, + getActionFilter: function () { + return systemvmActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.scale.up.system.vm'; + }, + notification: function (args) { + + return 'label.system.vm.scaled.up'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + + viewConsole: { + label: 'label.view.console', + action: { + externalLink: { + url: function (args) { + return clientConsoleUrl + '?cmd=access&vm=' + args.context.systemVMs[0].id; + }, + title: function (args) { + return args.context.systemVMs[0].id.substr(0, 8); + //title in window.open() can't have space nor longer than 8 characters. Otherwise, IE browser will have error. + }, + width: 820, + height: 640 + } + } + } + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + id: { + label: 'label.id' + }, + state: { + label: 'label.state' + }, + systemvmtype: { + label: 'label.type', + converter: function (args) { + if (args == "consoleproxy") + return 'label.console.proxy.vm'; else if (args == "secondarystoragevm") + return 'label.secondary.storage.vm'; else + return args; + } + }, + zonename: { + label: 'label.zone' + }, + publicip: { + label: 'label.public.ip' + }, + privateip: { + label: 'label.private.ip' + }, + linklocalip: { + label: 'label.linklocal.ip' + }, + hostname: { + label: 'label.host' + }, + gateway: { + label: 'label.gateway' + }, + created: { + label: 'label.created', + converter: cloudStack.converters.toLocalDate + }, + activeviewersessions: { + label: 'label.active.sessions' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listSystemVms&id=" + args.context.systemVMs[0].id), + dataType: "json", + async: true, + success: function (json) { + args.response.success({ + actionFilter: systemvmActionfilter, + data: json.listsystemvmsresponse.systemvm[0] + }); + } + }); + } + } + } + } + } + }, + + // Granular settings for zone + settings: { + title: 'label.settings', + custom: cloudStack.uiCustom.granularSettings({ + dataProvider: function (args) { + $.ajax({ + url: createURL('listConfigurations&zoneid=' + args.context.physicalResources[0].id), + data: listViewDataProvider(args, { + }, + { + searchBy: 'name' + }), + success: function (json) { + args.response.success({ + data: json.listconfigurationsresponse.configuration + }); + }, + + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + actions: { + edit: function (args) { + // call updateZoneLevelParamter + var data = { + name: args.data.jsonObj.name, + value: args.data.value + }; + + $.ajax({ + url: createURL('updateConfiguration&zoneid=' + args.context.physicalResources[0].id), + data: data, + success: function (json) { + var item = json.updateconfigurationresponse.configuration; + args.response.success({ + data: item + }); + }, + + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + }) + } + } + } + }, + pods: function () { + var listView = $.extend(true, { + }, + cloudStack.sections.system.subsections.pods.listView, { + dataProvider: function (args) { + var data = { + }; + listViewDataProvider(args, data); + + $.ajax({ + url: createURL('listPods'), + data: data, + success: function (json) { + args.response.success({ + data: json.listpodsresponse.pod + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + + detailView: { + updateContext: function (args) { + var zone; + + $.ajax({ + url: createURL('listZones'), + data: { + id: args.context.pods[0].zoneid + }, + async: false, + success: function (json) { + zone = json.listzonesresponse.zone[0]; + } + }); + + selectedZoneObj = zone; + + return { + zones:[zone] + }; + } + } + }); + + return listView; + }, + clusters: function () { + var listView = $.extend(true, { + }, + cloudStack.sections.system.subsections.clusters.listView, { + dataProvider: function (args) { + var data = { + }; + listViewDataProvider(args, data); + + $.ajax({ + url: createURL('listClusters'), + data: data, + success: function (json) { + args.response.success({ + data: json.listclustersresponse.cluster + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + + detailView: { + updateContext: function (args) { + var zone; + + $.ajax({ + url: createURL('listZones'), + data: { + id: args.context.clusters[0].zoneid + }, + async: false, + success: function (json) { + zone = json.listzonesresponse.zone[0]; + } + }); + + selectedZoneObj = zone; + + return { + zones:[zone] + }; + } + } + }); + + return listView; + }, + hosts: function () { + var listView = $.extend(true, { + }, + cloudStack.sections.system.subsections.hosts.listView, { + dataProvider: function (args) { + var data = { + type: 'routing' + }; + listViewDataProvider(args, data); + + $.ajax({ + url: createURL('listHosts'), + data: data, + success: function (json) { + var items = json.listhostsresponse.host; + if (items) { + $.each(items, function(idx, host) { + if (host && host.outofbandmanagement) { + items[idx].powerstate = host.outofbandmanagement.powerstate; + } + + if (host && host.hypervisor == "KVM" && host.state == 'Up' && host.details && host.details["secured"] != 'true') { + items[idx].state = 'Unsecure'; + } + + }); + } + + args.response.success({ + data: items + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + + detailView: { + updateContext: function (args) { + var zone; + + $.ajax({ + url: createURL('listZones'), + data: { + id: args.context.hosts[0].zoneid + }, + async: false, + success: function (json) { + zone = json.listzonesresponse.zone[0]; + } + }); + + selectedZoneObj = zone; + + return { + zones:[zone] + }; + } + } + }); + + return listView; + }, + primaryStorage: function () { + var listView = $.extend(true, { + }, + cloudStack.sections.system.subsections[ 'primary-storage'].listView, { + dataProvider: function (args) { + var data = { + }; + listViewDataProvider(args, data); + + $.ajax({ + url: createURL('listStoragePools'), + data: data, + success: function (json) { + args.response.success({ + data: json.liststoragepoolsresponse.storagepool + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + + detailView: { + updateContext: function (args) { + var zone; + + $.ajax({ + url: createURL('listZones'), + data: { + id: args.context.primarystorages[0].zoneid + }, + async: false, + success: function (json) { + zone = json.listzonesresponse.zone[0]; + } + }); + + selectedZoneObj = zone; + + return { + zones:[zone] + }; + } + } + }); + + return listView; + }, + + secondaryStorage: function () { + var listView = $.extend( + true, { + }, + cloudStack.sections.system.subsections[ 'secondary-storage'], { + sections: { + secondaryStorage: { + listView: { + dataProvider: function (args) { + var data = { + type: 'SecondaryStorage' + }; + listViewDataProvider(args, data); + + $.ajax({ + url: createURL('listImageStores'), + data: data, + success: function (json) { + var items = json.listimagestoresresponse.imagestore; + if (items != undefined) { + for (var i = 0; i < items.length; i++) { + processPropertiesInImagestoreObject(items[i]); + } + } + args.response.success({ + data: items + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + }, + cacheStorage: { + listView: { + dataProvider: function (args) { + var data = { + }; + listViewDataProvider(args, data); + + $.ajax({ + url: createURL('listSecondaryStagingStores'), + data: data, + success: function (json) { + args.response.success({ + data: json.listsecondarystagingstoreresponse.imagestore + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + + /* + , + detailView: { + updateContext: function (args) { + return { + zones: [{}] + }; + } + } + */ + } + } + } + }); + + return listView; + }, + systemVms: function () { + var listView = $.extend(true, { + }, + cloudStack.sections.system.subsections.systemVms.listView, { + dataProvider: function (args) { + var data = { + }; + listViewDataProvider(args, data); + + $.ajax({ + url: createURL('listSystemVms'), + data: data, + success: function (json) { + var systemvmObjs = json.listsystemvmsresponse.systemvm || []; + $(systemvmObjs).each(function(idx, item) { + var controlIp = item.linklocalip; + if (item.hypervisor == "VMware") { + var controlIp = item.privateip; + } + item.controlip = controlIp; + }); + + args.response.success({ + data: systemvmObjs + }); + } + }); + }, + + detailView: { + updateContext: function (args) { + var zone; + + $.ajax({ + url: createURL('listZones'), + data: { + id: args.context.systemVMs[0].zoneid + }, + async: false, + success: function (json) { + zone = json.listzonesresponse.zone[0]; + } + }); + + selectedZoneObj = zone; + + return { + zones:[zone] + }; + } + } + }); + + return listView; + }, + virtualRouters: function () { + var listView = $.extend(true, { + }, + cloudStack.sections.system.subsections.virtualRouters, { + sections: { + virtualRouterNoGrouping: { + listView: { + dataProvider: function (args) { + var data = { + }; + listViewDataProvider(args, data); + + var routers =[]; + + //get account-owned routers + $.ajax({ + url: createURL('listRouters'), + data: $.extend(data, { + listAll: true + }), + async: false, + success: function (json) { + var items = json.listroutersresponse.router ? json.listroutersresponse.router:[]; + $(items).map(function (index, item) { + routers.push(item); + }); + + //if account is specified in advanced search, don't search project-owned routers + var accountIsNotSpecifiedInAdvSearch = true; + if (args.filterBy != null) { + if (args.filterBy.advSearch != null && typeof(args.filterBy.advSearch) == "object") { //advanced search + if ('account' in args.filterBy.advSearch && args.filterBy.advSearch.account.length > 0) { + accountIsNotSpecifiedInAdvSearch = false; //since account and projectid can't be specified together + } + } + } + if (accountIsNotSpecifiedInAdvSearch) { + /* + * In project view, the first listRotuers API(without projectid=-1) will return the same objects as the second listRouters API(with projectid=-1), + * because in project view, all API calls are appended with projectid=[projectID]. + * Therefore, we only call the second listRouters API(with projectid=-1) in non-project view. + */ + if (cloudStack.context && cloudStack.context.projects == null) { //non-project view + $.ajax({ + url: createURL("listRouters&page=" + args.page + "&pagesize=" + pageSize + "&projectid=-1"), + async: false, + success: function (json) { + var items = json.listroutersresponse.router ? json.listroutersresponse.router:[]; + $(items).map(function (index, item) { + routers.push(item); + }); + } + }); + + } + } + + args.response.success({ + actionFilter: routerActionfilter, + data: $(routers).map(mapRouterType) + }); + } + }); + + args.response.success({ + actionFilter: routerActionfilter, + data: $(routers).map(mapRouterType) + }); + }, + + detailView: { + updateContext: function (args) { + var zone; + + $.ajax({ + url: createURL('listZones'), + data: { + id: args.context.routers[0].zoneid + }, + async: false, + success: function (json) { + zone = json.listzonesresponse.zone[0]; + } + }); + + selectedZoneObj = zone; + + return { + zones:[zone] + }; + } + } + } + } + } + }); + + return listView; + }, + + sockets: function () { + var listView = { + id: 'sockets', + fields: { + hypervisor: { + label: 'label.hypervisor' + }, + hosts: { + label: 'label.hosts' + }, + sockets: { + label: 'label.sockets' + } + }, + dataProvider: function (args) { + var array1 = []; + + // ***** non XenServer (begin) ***** + var hypervisors = ["Hyperv", "KVM", "VMware", "BareMetal", "LXC", "Ovm3"]; + + var supportSocketHypervisors = { + "Hyperv": 1, + "KVM": 1, + "VMware": 1, + "Ovm3": 1 + }; + + for (var h = 0; h < hypervisors.length; h++) { + var totalHostCount = 0; + var currentPage = 1; + var returnedHostCount = 0; + var returnedHostCpusocketsSum = 0; + + var callListHostsWithPage = function() { + $.ajax({ + url: createURL('listHosts'), + async: false, + data: { + type: 'routing', + hypervisor: hypervisors[h], + page: currentPage, + pagesize: pageSize //global variable + }, + success: function (json) { + if (json.listhostsresponse.count == undefined) { + return; + } + + totalHostCount = json.listhostsresponse.count; + returnedHostCount += json.listhostsresponse.host.length; + + var items = json.listhostsresponse.host; + for (var i = 0; i < items.length; i++) { + if (items[i].cpusockets != undefined && isNaN(items[i].cpusockets) == false) { + returnedHostCpusocketsSum += items[i].cpusockets; + } + } + + if (returnedHostCount < totalHostCount) { + currentPage++; + callListHostsWithPage(); + } + } + }); + } + + callListHostsWithPage(); + + if ((hypervisors[h] in supportSocketHypervisors) == false) { + returnedHostCpusocketsSum = 'N/A'; + } + + var hypervisorName = hypervisors[h]; + if (hypervisorName == "Hyperv") { + hypervisorName = "Hyper-V"; + } + + array1.push({ + hypervisor: hypervisorName, + hosts: totalHostCount, + sockets: returnedHostCpusocketsSum + }); + } + // ***** non XenServer (end) ***** + + + // ***** XenServer (begin) ***** + var totalHostCount = 0; + var currentPage = 1; + var returnedHostCount = 0; + + var returnedHostCountForXenServer700 = 0; //'XenServer 7.0.0' + var returnedHostCpusocketsSumForXenServer700 = 0; + + var returnedHostCountForXenServer650 = 0; //'XenServer 6.5.0' + var returnedHostCpusocketsSumForXenServer650 = 0; + + var returnedHostCountForXenServer620 = 0; //'XenServer 6.2.0' + var returnedHostCpusocketsSumForXenServer620 = 0; + + var returnedHostCountForXenServer61x = 0; //'XenServer 6.1.x and before' + + var callListHostsWithPage = function() { + $.ajax({ + url: createURL('listHosts'), + async: false, + data: { + type: 'routing', + hypervisor: 'XenServer', + page: currentPage, + pagesize: pageSize //global variable + }, + success: function(json) { + if (json.listhostsresponse.count == undefined) { + return; + } + + totalHostCount = json.listhostsresponse.count; + returnedHostCount += json.listhostsresponse.host.length; + + var items = json.listhostsresponse.host; + for (var i = 0; i < items.length; i++) { + if (items[i].hypervisorversion == "7.0.0") { + returnedHostCountForXenServer700 ++; + if (items[i].cpusockets != undefined && isNaN(items[i].cpusockets) == false) { + returnedHostCpusocketsSumForXenServer700 += items[i].cpusockets; + } + } else if (items[i].hypervisorversion == "6.5.0") { + returnedHostCountForXenServer650 ++; + if (items[i].cpusockets != undefined && isNaN(items[i].cpusockets) == false) { + returnedHostCpusocketsSumForXenServer650 += items[i].cpusockets; + } + } else if (items[i].hypervisorversion == "6.2.0") { + returnedHostCountForXenServer620 ++; + if (items[i].cpusockets != undefined && isNaN(items[i].cpusockets) == false) { + returnedHostCpusocketsSumForXenServer620 += items[i].cpusockets; + } + } else { + returnedHostCountForXenServer61x++; + } + } + + if (returnedHostCount < totalHostCount) { + currentPage++; + callListHostsWithPage(); + } + } + }); + } + + callListHostsWithPage(); + + array1.push({ + hypervisor: 'XenServer 7.0.0', + hosts: returnedHostCountForXenServer700, + sockets: returnedHostCpusocketsSumForXenServer700 + }); + + array1.push({ + hypervisor: 'XenServer 6.5.0', + hosts: returnedHostCountForXenServer650, + sockets: returnedHostCpusocketsSumForXenServer650 + }); + + array1.push({ + hypervisor: 'XenServer 6.2.0', + hosts: returnedHostCountForXenServer620, + sockets: returnedHostCpusocketsSumForXenServer620 + }); + + array1.push({ + hypervisor: 'XenServer 6.1.x and before', + hosts: returnedHostCountForXenServer61x, + sockets: 'N/A' + }); + + // ***** XenServer (end) ***** + + + args.response.success({ + data: array1 + }); + + } + }; + + return listView; + }, + + managementServers: function () { + var listView = { + id: 'managementservers', + fields: { + name: { + label: 'label.name' + }, + id: { + label: 'label.uuid' + }, + state: { + label: 'label.state', + indicator: { + 'Up': 'on', + 'Down': 'off' + } + }, + version: { + label: 'label.version' + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL('listManagementServers'), + async: false, + success: function (json) { + args.response.success({ data: json.listmanagementserversresponse.managementserver }); + } + }); + } + }; + return listView; + } + } + } + } + }, + subsections: { + virtualRouters: { + sectionSelect: { + label: 'label.select-view', + preFilter: function(args) { + //Only clicking ViewAll Link("view all Virtual Routers") in "Virtual Routers group by XXXXXXX" detailView will have "routerGroupByXXXXXXX" included in args.context + if ("routerGroupByZone" in args.context) { + return ["routerGroupByZone"]; // read-only (i.e. text "group by Zone") + } else if ( "routerGroupByPod" in args.context) { + return ["routerGroupByPod"]; // read-only (i.e. text "group by Pod") + } else if ("routerGroupByCluster" in args.context) { + return ["routerGroupByCluster"]; // read-only (i.e. text "group by Cluster") + } else if ("routerGroupByAccount" in args.context) { + return ["routerGroupByAccount"]; // read-only (i.e. text "group by Account") + } else { + return ["routerNoGroup", "routerGroupByZone", "routerGroupByPod", "routerGroupByCluster", "routerGroupByAccount"]; //editable dropdown + } + } + }, + sections: { + routerNoGroup: { + id: 'routers', + type: 'select', + title: 'label.no.grouping', + listView: { + id: 'routers', + label: 'label.virtual.appliances', + horizontalOverflow: true, + fields: { + name: { + label: 'label.name' + }, + publicip: { + label: 'label.ip' + }, + routerType: { + label: 'label.type' + }, + guestnetworkname: { + label: 'label.network' + }, + account: { + label: 'label.account' + }, + hostname: { + label: 'label.host' + }, + state: { + converter: function (str) { + // For localization + return str; + }, + label: 'label.status', + indicator: { + 'Running': 'on', + 'Stopped': 'off', + 'Error': 'off', + 'Alert': 'warning' + } + }, + healthchecksfailed: { + converter: function (str) { + if (str) return 'Failed' + return 'Passed'; + }, + label: 'label.health.check', + indicator: { + false: 'on', + true: 'warning' + } + }, + requiresupgrade: { + label: 'label.requires.upgrade', + converter: cloudStack.converters.toBooleanText + } + }, + preFilter: function () { + if (!g_routerHealthChecksEnabled) { + return ['healthchecksfailed'] + } + return [] + }, + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + + var data2 = { + // forvpc: false + }; + + if (args.context != undefined) { + if ("routerGroupByZone" in args.context) { + $.extend(data2, { + zoneid: args.context.routerGroupByZone[0].id + }) + } else if ("routerGroupByPod" in args.context) { + $.extend(data2, { + podid: args.context.routerGroupByPod[0].id + }) + } else if ("routerGroupByCluster" in args.context) { + $.extend(data2, { + clusterid: args.context.routerGroupByCluster[0].id + }) + } else if ("routerGroupByAccount" in args.context) { + $.extend(data2, { + account: args.context.routerGroupByAccount[0].name, + domainid: args.context.routerGroupByAccount[0].domainid + }) + } + if ("networks" in args.context) { + $.extend(data2, { + networkid: args.context.networks[0].id + }) + } + if ("vpc" in args.context) { + $.extend(data2, { + vpcid: args.context.vpc[0].id + }) + } + } + + var routers =[]; + $.ajax({ + url: createURL("listRouters&listAll=true&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + data: data2, + success: function (json) { + var items = json.listroutersresponse.router ? + json.listroutersresponse.router:[]; + + $(items).map(function (index, item) { + routers.push(item); + }); + + /* + * In project view, the first listRotuers API(without projectid=-1) will return the same objects as the second listRouters API(with projectid=-1), + * because in project view, all API calls are appended with projectid=[projectID]. + * Therefore, we only call the second listRouters API(with projectid=-1) in non-project view. + */ + if (cloudStack.context && cloudStack.context.projects == null) { //non-project view + /* + * account parameter(account+domainid) and project parameter(projectid) are not allowed to be passed together to listXXXXXXX API. + * So, remove account parameter(account+domainid) from data2 + */ + if ("account" in data2) { + delete data2.account; + } + if ("domainid" in data2) { + delete data2.domainid; + } + + $.ajax({ + url: createURL("listRouters&page=" + args.page + "&pagesize=" + pageSize + array1.join("") + "&projectid=-1"), + data: data2, + async: false, + success: function (json) { + var items = json.listroutersresponse.router ? + json.listroutersresponse.router:[]; + + var items = json.listroutersresponse.router ? + json.listroutersresponse.router:[]; + + $(items).map(function (index, item) { + routers.push(item); + }); + } + }); + } + + args.response.success({ + actionFilter: routerActionfilter, + data: $(routers).map(mapRouterType) + }); + } + }); + }, + detailView: { + name: 'label.virtual.appliance.details', + viewAll: [{ + label: 'label.account', + path: 'accounts', + preFilter: function(args) { + if (args.context.routers[0].projectid) + return false; + if (args.context.routers[0].account == 'system') + return false; + return true; + } + }, { + label: 'label.networks', + path: 'network', + }, { + label: 'label.instances', + path: 'instances' + }], + actions: { + start: { + label: 'label.action.start.router', + messages: { + confirm: function (args) { + return 'message.action.start.router'; + }, + notification: function (args) { + return 'label.action.start.router'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('startRouter&id=' + args.context.routers[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.startrouterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.router; + }, + getActionFilter: function () { + return routerActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + stop: { + label: 'label.action.stop.router', + createForm: { + title: 'label.action.stop.router', + desc: 'message.action.stop.router', + fields: { + forced: { + label: 'force.stop', + isBoolean: true, + isChecked: false + } + } + }, + messages: { + notification: function (args) { + return 'label.action.stop.router'; + } + }, + action: function (args) { + var array1 =[]; + array1.push("&forced=" + (args.data.forced == "on")); + $.ajax({ + url: createURL('stopRouter&id=' + args.context.routers[0].id + array1.join("")), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.stoprouterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.router; + }, + getActionFilter: function () { + return routerActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + upgradeRouterToUseNewerTemplate: { + label: 'label.upgrade.router.newer.template', + messages: { + confirm: function (args) { + return 'message.confirm.upgrade.router.newer.template'; + }, + notification: function (args) { + return 'label.upgrade.router.newer.template'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('upgradeRouterTemplate'), + data: { + id: args.context.routers[0].id + }, + success: function (json) { + var jobs = json.upgraderoutertemplateresponse.asyncjobs; + if (jobs != undefined) { + args.response.success({ + _custom: { + jobId: jobs[0].jobid + } + }); + } + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + 'remove': { + label: 'label.destroy.router', + messages: { + confirm: function (args) { + if (args && args.context && args.context.routers[0]) { + if (args.context.routers[0].state == 'Running') { + return dictionary['message.action.stop.router'] + ' ' + dictionary['message.confirm.destroy.router']; + } + } + return 'message.confirm.destroy.router'; + }, + notification: function (args) { + return 'label.destroy.router'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("destroyRouter&id=" + args.context.routers[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.destroyrouterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + restart: { + label: 'label.action.reboot.router', + messages: { + confirm: function (args) { + return 'message.action.reboot.router'; + }, + notification: function (args) { + return 'label.action.reboot.router'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('rebootRouter&id=' + args.context.routers[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.rebootrouterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.router; + }, + getActionFilter: function () { + return routerActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + migrate: { + label: 'label.action.migrate.router', + createForm: { + title: 'label.action.migrate.router', + desc: '', + fields: { + hostId: { + label: 'label.host', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL("findHostsForMigration&VirtualMachineId=" + args.context.routers[0].id), + dataType: "json", + async: true, + success: function (json) { + var hostObjs = json.findhostsformigrationresponse.host; + var items =[]; + $(hostObjs).each(function () { + items.push({ + id: this.id, + description: (this.name + " (" + (this.suitableformigration ? "Suitable": "Not Suitable") + ")") + }); + }); + args.response.success({ + data: items + }); + } + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + } + } + }, + messages: { + notification: function (args) { + return 'label.action.migrate.router'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("migrateSystemVm&hostid=" + args.data.hostId + "&virtualmachineid=" + args.context.routers[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.migratesystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + //return json.queryasyncjobresultresponse.jobresult.systemvminstance; //not all properties returned in systemvminstance + $.ajax({ + url: createURL("listRouters&id=" + json.queryasyncjobresultresponse.jobresult.systemvm.id), + dataType: "json", + async: false, + success: function (json) { + var items = json.listroutersresponse.router; + if (items != null && items.length > 0) { + return items[0]; + } + } + }); + }, + getActionFilter: function () { + return routerActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + // VR Diagnostics + diagnostics: { + label: 'label.action.run.diagnostics', + messages: { + notification: function (args) { + return 'label.action.run.diagnostics'; + }, + complete: function(args) { + var exitcode = _l('message.diagnostics.exitcode'); + exitcode = exitcode.replace('var', args.exitcode); + var stderr = _l('message.diagnostics.stderr'); + stderr = stderr.replace('var', args.stderr); + var stdout = _l('message.diagnostics.stdout'); + stdout = stdout.replace('var', args.stdout); + var msg = "
    " + exitcode + "

    " + stderr + "

    " + stdout + "
    "; + return msg; + } + }, + createForm: { + title: 'label.action.run.diagnostics', + desc: '', + fields: { + type: { + label: 'label.run.diagnostics.type', + validation: { + required: true + }, + select: function (args) { + var items = []; + items.push({ + id: "ping", + description: "Ping" + }); + items.push({ + id: "traceroute", + description: "Traceroute" + }); + items.push({ + id: "arping", + description: "Arping" + }); + args.response.success({ + data: items + }); + } + }, + destination: { + label: 'label.run.diagnostics.destination', + validation: { + required: true + } + }, + extra: { + label: 'label.run.diagnostics.extra' + } + + } + }, + action: function (args) { + $.ajax({ + url: createURL("runDiagnostics&targetid=" + args.context.routers[0].id + "&ipaddress=" + args.data.destination + "&type=" + args.data.type + "¶ms=" + args.data.extra), + dataType: "json", + async: true, + success: function(json) { + var jid = json.rundiagnosticsresponse.jobid; + args.response.success({ + _custom: { + jobId : jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.diagnostics; + + }, + getActionFilter: function(){ + return routerActionfilter; + } + } + + }); + } + }); //end ajax + }, + notification: { + poll: pollAsyncJobResult + } + }, + + retrieveDiagnostics: { + label: 'label.action.get.diagnostics', + messages: { + notification: function (args) { + return 'label.action.get.diagnostics'; + }, + complete: function(args) { + var url = args.url; + var htmlMsg = _l('message.download.diagnostics'); + var htmlMsg2 = htmlMsg.replace(/#/, url).replace(/00000/, url); + return htmlMsg2; + } + }, + createForm: { + title: 'label.action.get.diagnostics', + desc: 'label.get.diagnostics.desc', + fields: { + files: { + label: 'label.get.diagnostics.files' + } + } + }, + action: function (args) { + $.ajax({ + url: createURL("getDiagnosticsData&targetid=" + args.context.routers[0].id + "&files=" + args.data.files), + dataType: "json", + async: true, + success: function(json) { + var jid = json.getdiagnosticsdataresponse.jobid; + args.response.success({ + _custom: { + jobId : jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.diagnostics; + + }, + getActionFilter: function(){ + return systemvmActionfilter; + } + } + + }); + } + }); //end ajax + }, + notification: { + poll: pollAsyncJobResult + } + }, + + scaleUp: { //*** Infrastructure > Virtual Routers > change service offering *** + label: 'label.change.service.offering', + createForm: { + title: 'label.change.service.offering', + desc: function (args) { + var description = ''; + var vmObj = args.jsonObj; + //if (vmObj.state == 'Running' && vmObj.hypervisor == 'VMware') { //needs to wait for API fix that will return hypervisor property + if (vmObj.state == 'Running') { + description = 'message.read.admin.guide.scaling.up'; + } + return description; + }, + fields: { + serviceOfferingId: { + label: 'label.compute.offering', + select: function (args) { + $.ajax({ + url: createURL('listServiceOfferings'), + data: { + issystem: true, + systemvmtype: 'domainrouter', + virtualmachineid: args.context.routers[0].id + }, + success: function (json) { + var serviceofferings = json.listserviceofferingsresponse.serviceoffering; + var items =[]; + $(serviceofferings).each(function () { + // if(this.id != args.context.routers[0].serviceofferingid) { + items.push({ + id: this.id, + description: this.name + }); + //default one (i.e. "System Offering For Software Router") doesn't have displaytext property. So, got to use name property instead. + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + + action: function (args) { + $.ajax({ + url: createURL("scaleSystemVm&id=" + args.context.routers[0].id + "&serviceofferingid=" + args.data.serviceOfferingId), + dataType: "json", + async: true, + success: function (json) { + var jid = json.changeserviceforsystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.systemvm; + }, + getActionFilter: function () { + return routerActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.scale.up.router.vm'; + }, + notification: function (args) { + + return 'label.router.vm.scaled.up'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + + viewConsole: { + label: 'label.view.console', + action: { + externalLink: { + url: function (args) { + return clientConsoleUrl + '?cmd=access&vm=' + args.context.routers[0].id; + }, + title: function (args) { + return args.context.routers[0].id.substr(0, 8); + //title in window.open() can't have space nor longer than 8 characters. Otherwise, IE browser will have error. + }, + width: 820, + height: 640 + } + } + }, + + healthChecks: { + label: 'label.action.router.health.checks', + createForm: { + title: 'label.action.router.health.checks', + desc: 'message.action.router.health.checks', + fields: { + performfreshchecks: { + label: 'label.perform.fresh.checks', + isBoolean: true + } + } + }, + action: function (args) { + if (!g_routerHealthChecksEnabled) { + cloudStack.dialog.notice({ + message: 'Router health checks are disabled. Please enable router.health.checks.enabled to execute this action' + }) + args.response.success() + return + } + var data = { + 'routerid': args.context.routers[0].id, + 'performfreshchecks': (args.data.performfreshchecks === 'on') + }; + $.ajax({ + url: createURL('getRouterHealthCheckResults'), + dataType: 'json', + data: data, + async: true, + success: function (json) { + var healthChecks = json.getrouterhealthcheckresultsresponse.routerhealthchecks.healthchecks + var numChecks = healthChecks.length + var failedChecks = 0 + $.each(healthChecks, function(idx, check) { + if (!check.success) failedChecks = failedChecks + 1 + }) + cloudStack.dialog.notice({ + message: 'Found ' + numChecks + ' checks for router, with ' + failedChecks + ' failing checks. Please visit router > Health Checks tab to see details' + }) + args.response.success(); + } + }); + }, + messages: { + notification: function(args) { + return 'label.action.router.health.checks' + } + } + } + }, + tabs: { + details: { + title: 'label.details', + preFilter: function (args) { + var hiddenFields =[]; + if (! args.context.routers[0].project) { + hiddenFields.push('project'); + hiddenFields.push('projectid'); + } + $.ajax({ + url: createURL('listZones'), + data: { + id: args.context.routers[0].zoneid + }, + async: false, + success: function (json) { + if (json.listzonesresponse.zone != undefined) { + var zoneObj = json.listzonesresponse.zone[0]; + if (zoneObj.networktype == 'Basic') { + hiddenFields.push('publicip'); + //In Basic zone, guest IP is public IP. So, publicip is not returned by listRouters API. Only guestipaddress is returned by listRouters API. + } + } + } + }); + + if ('routers' in args.context && args.context.routers[0].vpcid != undefined) { + hiddenFields.push('guestnetworkid'); + hiddenFields.push('guestnetworkname'); + } else if ('routers' in args.context && args.context.routers[0].guestnetworkid != undefined) { + hiddenFields.push('vpcid'); + hiddenFields.push('vpcname'); + } + + return hiddenFields; + }, + fields:[ { + name: { + label: 'label.name' + }, + project: { + label: 'label.project' + } + }, + { + id: { + label: 'label.id' + }, + projectid: { + label: 'label.project.id' + }, + state: { + label: 'label.state' + }, + version: { + label: 'label.version' + }, + requiresupgrade: { + label: 'label.requires.upgrade', + converter: cloudStack.converters.toBooleanText + }, + guestnetworkid: { + label: 'label.network.id' + }, + guestnetworkname: { + label: 'label.network.name' + }, + vpcid: { + label: 'label.vpc.id' + }, + vpcname: { + label: 'label.vpc' + }, + publicip: { + label: 'label.public.ip' + }, + guestipaddress: { + label: 'label.guest.ip' + }, + linklocalip: { + label: 'label.linklocal.ip' + }, + hostname: { + label: 'label.host' + }, + serviceofferingname: { + label: 'label.compute.offering' + }, + networkdomain: { + label: 'label.network.domain' + }, + domain: { + label: 'label.domain' + }, + account: { + label: 'label.account' + }, + created: { + label: 'label.created', + converter: cloudStack.converters.toLocalDate + }, + isredundantrouter: { + label: 'label.redundant.router', + converter: cloudStack.converters.toBooleanText + }, + redundantRouterState: { + label: 'label.redundant.state' + }, + vpcid: { + label: 'label.vpc.id' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listRouters&id=" + args.context.routers[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jsonObj = json.listroutersresponse.router[0]; + addExtraPropertiesToRouterInstanceObject(jsonObj); + args.response.success({ + actionFilter: routerActionfilter, + data: jsonObj + }); + } + }); + } + }, + nics: { + title: 'label.nics', + multiple: true, + fields:[ { + name: { + label: 'label.name', + header: true + }, + type: { + label: 'label.type' + }, + traffictype: { + label: 'label.traffic.type' + }, + networkname: { + label: 'label.network.name' + }, + netmask: { + label: 'label.netmask' + }, + ipaddress: { + label: 'label.ip.address' + }, + id: { + label: 'label.id' + }, + networkid: { + label: 'label.network.id' + }, + isolationuri: { + label: 'label.isolation.uri' + }, + broadcasturi: { + label: 'label.broadcast.uri' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listRouters&id=" + args.context.routers[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jsonObj = json.listroutersresponse.router[0].nic; + + args.response.success({ + actionFilter: routerActionfilter, + data: $.map(jsonObj, function (nic, index) { + var name = 'NIC ' + (index + 1); + if (nic.isdefault) { + name += ' (' + _l('label.default') + ')'; + } + return $.extend(nic, { + name: name + }); + }) + }); + } + }); + } + }, + healthCheckResults: { + title: 'label.router.health.checks', + listView: { + id: 'routerHealthCheckResults', + label: 'label.router.health.checks', + hideToolbar: true, + fields: { + checkname: { + label: 'label.router.health.check.name' + }, + checktype: { + label: 'label.router.health.check.type' + }, + success: { + label: 'label.router.health.check.success', + converter: function (args) { + if (args) { + return _l('True'); + } else { + return _l('False'); + } + }, + indicator: { + true: 'on', + false: 'off' + } + }, + lastupdated: { + label: 'label.router.health.check.last.updated' + } + }, + actions: { + details: { + label: 'label.router.health.check.details', + action: { + custom: function (args) { + cloudStack.dialog.notice({ + message: args.context.routerHealthCheckResults[0].details + }) + } + } + } + }, + dataProvider: function(args) { + if (!g_routerHealthChecksEnabled) { + cloudStack.dialog.notice({ + message: 'Router health checks are disabled. Please enable router.health.checks.enabled to get data' + }) + args.response.success({}) + return + } + if (args.page > 1) { + // Only one page is supported as it's not list command. + args.response.success({}); + return + } + + $.ajax({ + url: createURL('getRouterHealthCheckResults'), + data: { + 'routerid': args.context.routers[0].id + }, + success: function (json) { + var hcData = json.getrouterhealthcheckresultsresponse.routerhealthchecks.healthchecks + args.response.success({ + data: hcData + }); + } + }); + } + } + } + } + } + } + }, + routerGroupByZone: { + id: 'routerGroupByZone', + type: 'select', + title: 'label.group.by.zone', + listView: { + id: 'routerGroupByZone', + label: 'label.virtual.appliances', + fields: { + name: { + label: 'label.zone' + }, + routerCount: { + label: 'label.total.virtual.routers' + }, + routerRequiresUpgrade: { + label: 'label.upgrade.required', + converter: function (args) { + if (args > 0) { + return _l('label.yes'); + } else { + return _l('label.no'); + } + } + } + }, + + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + $.ajax({ + url: createURL("listZones&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + dataType: "json", + async: true, + success: function (json) { + var groupbyObjs = json.listzonesresponse.zone; + if (groupbyObjs != null) { + addExtraPropertiesToGroupbyObjects(groupbyObjs, 'zoneid'); + } + args.response.success({ + data: groupbyObjs + }); + } + }); + }, + detailView: { + name: 'label.virtual.routers.group.zone', + viewAll: { + path: '_zone.virtualRouters', + label: 'label.virtual.appliances' + }, + actions: { + upgradeRouterToUseNewerTemplate: { + label: 'label.upgrade.router.newer.template', + messages: { + confirm: function (args) { + return 'message.confirm.upgrade.routers.newtemplate'; + }, + notification: function (args) { + return 'label.upgrade.router.newer.template'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('upgradeRouterTemplate'), + data: { + zoneid: args.context.routerGroupByZone[0].id + }, + success: function (json) { + var jobs = json.upgraderoutertemplateresponse.asyncjobs; + if (jobs != undefined) { + args.response.success({ + _custom: { + jobId: jobs[0].jobid + } + }); + } + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.virtual.routers.group.zone', + fields:[ { + name: { + label: 'label.zone' + } + }, + { + routerCount: { + label: 'label.total.virtual.routers' + }, + routerRequiresUpgrade: { + label: 'label.upgrade.required', + converter: function (args) { + if (args > 0) { + return _l('label.yes'); + } else { + return _l('label.no'); + } + } + }, + numberOfRouterRequiresUpgrade: { + label: 'label.total.virtual.routers.upgrade' + } + }], + dataProvider: function (args) { + addExtraPropertiesToGroupbyObject(args.context.routerGroupByZone[0], 'zoneid'); + args.response.success({ + data: args.context.routerGroupByZone[0], + actionFilter: routerGroupActionfilter + }); + } + } + } + } + } + }, + routerGroupByPod: { + id: 'routerGroupByPod', + type: 'select', + title: 'label.group.by.pod', + listView: { + id: 'routerGroupByPod', + label: 'label.virtual.appliances', + fields: { + name: { + label: 'label.pod' + }, + routerCount: { + label: 'label.total.virtual.routers' + }, + routerRequiresUpgrade: { + label: 'label.upgrade.required', + converter: function (args) { + if (args > 0) { + return _l('label.yes'); + } else { + return _l('label.no'); + } + } + } + }, + + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + $.ajax({ + url: createURL("listPods&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + dataType: "json", + async: true, + success: function (json) { + var groupbyObjs = json.listpodsresponse.pod; + if (groupbyObjs != null) { + addExtraPropertiesToGroupbyObjects(groupbyObjs, 'podid'); + } + args.response.success({ + data: groupbyObjs + }); + } + }); + }, + detailView: { + name: 'label.virtual.routers.group.pod', + viewAll: { + path: '_zone.virtualRouters', + label: 'label.virtual.appliances' + }, + actions: { + upgradeRouterToUseNewerTemplate: { + label: 'label.upgrade.router.newer.template', + messages: { + confirm: function (args) { + return 'message.confirm.upgrade.routers.pod.newtemplate'; + }, + notification: function (args) { + return 'label.upgrade.router.newer.template'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('upgradeRouterTemplate'), + data: { + podid: args.context.routerGroupByPod[0].id + }, + success: function (json) { + var jobs = json.upgraderoutertemplateresponse.asyncjobs; + if (jobs != undefined) { + args.response.success({ + _custom: { + jobId: jobs[0].jobid + } + }); + } + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.virtual.routers.group.pod', + fields:[ { + name: { + label: 'label.pod' + } + }, + { + routerCount: { + label: 'label.total.virtual.routers' + }, + routerRequiresUpgrade: { + label: 'label.upgrade.required', + converter: function (args) { + if (args > 0) { + return _l('label.yes'); + } else { + return _l('label.no'); + } + } + }, + numberOfRouterRequiresUpgrade: { + label: 'label.total.virtual.routers.upgrade' + }, + zonename: { + label: 'label.zone' + } + }], + dataProvider: function (args) { + addExtraPropertiesToGroupbyObject(args.context.routerGroupByPod[0], 'podid'); + args.response.success({ + data: args.context.routerGroupByPod[0], + actionFilter: routerGroupActionfilter + }); + } + } + } + } + } + }, + routerGroupByCluster: { + id: 'routerGroupByCluster', + type: 'select', + title: 'label.group.by.cluster', + listView: { + id: 'routerGroupByCluster', + label: 'label.virtual.appliances', + fields: { + name: { + label: 'label.cluster' + }, + routerCount: { + label: 'label.total.virtual.routers' + }, + routerRequiresUpgrade: { + label: 'label.upgrade.required', + converter: function (args) { + if (args > 0) { + return _l('label.yes'); + } else { + return _l('label.no'); + } + } + } + }, + + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + $.ajax({ + url: createURL("listClusters&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + dataType: "json", + async: true, + success: function (json) { + var groupbyObjs = json.listclustersresponse.cluster; + if (groupbyObjs != null) { + addExtraPropertiesToGroupbyObjects(groupbyObjs, 'clusterid'); + } + args.response.success({ + data: groupbyObjs + }); + } + }); + }, + detailView: { + name: 'label.virtual.routers.group.cluster', + viewAll: { + path: '_zone.virtualRouters', + label: 'label.virtual.appliances' + }, + actions: { + upgradeRouterToUseNewerTemplate: { + label: 'label.upgrade.router.newer.template', + messages: { + confirm: function (args) { + return 'message.confirm.upgrade.routers.cluster.newtemplate'; + }, + notification: function (args) { + return 'label.upgrade.router.newer.template'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('upgradeRouterTemplate'), + data: { + clusterid: args.context.routerGroupByCluster[0].id + }, + success: function (json) { + var jobs = json.upgraderoutertemplateresponse.asyncjobs; + if (jobs != undefined) { + args.response.success({ + _custom: { + jobId: jobs[0].jobid + } + }); + } + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.virtual.routers.group.cluster', + fields:[ { + name: { + label: 'label.cluster' + } + }, + { + routerCount: { + label: 'label.total.virtual.routers' + }, + routerRequiresUpgrade: { + label: 'label.upgrade.required', + converter: function (args) { + if (args > 0) { + return _l('label.yes'); + } else { + return _l('label.no'); + } + } + }, + numberOfRouterRequiresUpgrade: { + label: 'label.total.virtual.routers.upgrade' + }, + podname: { + label: 'label.pod' + }, + zonename: { + label: 'label.zone.lower' + } + }], + dataProvider: function (args) { + addExtraPropertiesToGroupbyObject(args.context.routerGroupByCluster[0], 'clusterid'); + args.response.success({ + data: args.context.routerGroupByCluster[0], + actionFilter: routerGroupActionfilter + }); + } + } + } + } + } + }, + routerGroupByAccount: { + id: 'routerGroupByAccount', + type: 'select', + title: 'label.group.by.account', + listView: { + id: 'routerGroupByAccount', + label: 'label.virtual.appliances', + fields: { + name: { + label: 'label.account' + }, + domain: { + label: 'label.domain' + }, + routerCount: { + label: 'label.total.virtual.routers' + }, + routerRequiresUpgrade: { + label: 'label.upgrade.required', + converter: function (args) { + if (args > 0) { + return _l('label.yes'); + } else { + return _l('label.no'); + } + } + } + }, + + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + $.ajax({ + url: createURL("listAccounts&listAll=true&details=min&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + success: function (json) { + var accountObjs = json.listaccountsresponse.account; + if (accountObjs != null) { + for (var i = 0; i < accountObjs.length; i++) { + var currentPage = 1; + $.ajax({ + url: createURL('listRouters'), + data: { + account: accountObjs[i].name, + domainid: accountObjs[i].domainid, + listAll: true, + page: currentPage, + pagesize: pageSize //global variable + }, + async: false, + success: function (json) { + if (json.listroutersresponse.count != undefined) { + accountObjs[i].routerCount = json.listroutersresponse.count; + var routerCountFromAllPages = json.listroutersresponse.count; + var routerCountFromFirstPageToCurrentPage = json.listroutersresponse.router.length; + var routerRequiresUpgrade = 0; + + var items = json.listroutersresponse.router; + for (var k = 0; k < items.length; k++) { + if (items[k].requiresupgrade) { + routerRequiresUpgrade++; + } + } + + var callListApiWithPage = function () { + $.ajax({ + url: createURL('listRouters'), + async: false, + data: { + account: accountObjs[i].name, + domainid: accountObjs[i].domainid, + listAll: true, + page: currentPage, + pagesize: pageSize //global variable + }, + success: function (json) { + routerCountFromFirstPageToCurrentPage += json.listroutersresponse.router.length; + var items = json.listroutersresponse.router; + for (var k = 0; k < items.length; k++) { + if (items[k].requiresupgrade) { + routerRequiresUpgrade++; + } + } + if (routerCountFromFirstPageToCurrentPage < routerCountFromAllPages) { + currentPage++; + callListApiWithPage(); + } + } + }); + } + if (routerCountFromFirstPageToCurrentPage < routerCountFromAllPages) { + currentPage++; + callListApiWithPage(); + } + accountObjs[i].routerRequiresUpgrade = routerRequiresUpgrade; + } else { + accountObjs[i].routerCount = 0; + accountObjs[i].routerRequiresUpgrade = 0; + } + } + }); + } + } + args.response.success({ + data: accountObjs + }); + } + }); + }, + detailView: { + name: 'label.virtual.routers.group.account', + viewAll: { + path: '_zone.virtualRouters', + label: 'label.virtual.appliances' + }, + actions: { + upgradeRouterToUseNewerTemplate: { + label: 'label.upgrade.router.newer.template', + messages: { + confirm: function (args) { + return 'message.confirm.upgrade.routers.account.newtemplate'; + }, + notification: function (args) { + return 'label.upgrade.router.newer.template'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('upgradeRouterTemplate'), + data: { + account: args.context.routerGroupByAccount[0].name, + domainid: args.context.routerGroupByAccount[0].domainid + }, + success: function (json) { + var jobs = json.upgraderoutertemplateresponse.asyncjobs; + if (jobs != undefined) { + args.response.success({ + _custom: { + jobId: jobs[0].jobid + } + }); + } + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.virtual.routers.group.account', + fields:[ { + name: { + label: 'label.account' + }, + domain: { + label: 'label.domain' + } + }, + { + routerCount: { + label: 'label.total.virtual.routers' + }, + routerRequiresUpgrade: { + label: 'label.upgrade.required', + converter: function (args) { + if (args > 0) { + return _l('label.yes'); + } else { + return _l('label.no'); + } + } + }, + numberOfRouterRequiresUpgrade: { + label: 'label.total.virtual.routers.upgrade' + } + }], + dataProvider: function (args) { + var currentPage = 1; + $.ajax({ + url: createURL('listRouters'), + data: { + account: args.context.routerGroupByAccount[0].name, + domainid: args.context.routerGroupByAccount[0].domainid, + listAll: true, + page: currentPage, + pagesize: pageSize //global variable + }, + async: false, + success: function (json) { + if (json.listroutersresponse.count != undefined) { + args.context.routerGroupByAccount[0].routerCount = json.listroutersresponse.count; + var routerCountFromAllPages = json.listroutersresponse.count; + var routerCountFromFirstPageToCurrentPage = json.listroutersresponse.router.length; + var routerRequiresUpgrade = 0; + + var items = json.listroutersresponse.router; + for (var k = 0; k < items.length; k++) { + if (items[k].requiresupgrade) { + routerRequiresUpgrade++; + } + } + + var callListApiWithPage = function () { + $.ajax({ + url: createURL('listRouters'), + async: false, + data: { + account: args.context.routerGroupByAccount[0].name, + domainid: args.context.routerGroupByAccount[0].domainid, + listAll: true, + page: currentPage, + pagesize: pageSize //global variable + }, + success: function (json) { + routerCountFromFirstPageToCurrentPage += json.listroutersresponse.router.length; + var items = json.listroutersresponse.router; + for (var k = 0; k < items.length; k++) { + if (items[k].requiresupgrade) { + routerRequiresUpgrade++; + } + } + if (routerCountFromFirstPageToCurrentPage < routerCountFromAllPages) { + currentPage++; + callListApiWithPage(); + } + } + }); + } + if (routerCountFromFirstPageToCurrentPage < routerCountFromAllPages) { + currentPage++; + callListApiWithPage(); + } + args.context.routerGroupByAccount[0].routerRequiresUpgrade = routerRequiresUpgrade; + args.context.routerGroupByAccount[0].numberOfRouterRequiresUpgrade = routerRequiresUpgrade; + } else { + args.context.routerGroupByAccount[0].routerCount = 0; + args.context.routerGroupByAccount[0].routerRequiresUpgrade = 0; + args.context.routerGroupByAccount[0].numberOfRouterRequiresUpgrade = 0; + } + } + }); + setTimeout(function () { + args.response.success({ + data: args.context.routerGroupByAccount[0], + actionFilter: routerGroupActionfilter + }); + }); + } + } + } + } + } + } + } + }, + systemVms: { + listView: { + label: 'label.system.vms', + id: 'systemVMs', + fields: { + name: { + label: 'label.name' + }, + systemvmtype: { + label: 'label.type', + converter: function (args) { + if (args == "consoleproxy") + return "Console Proxy VM"; else if (args == "secondarystoragevm") + return "Secondary Storage VM"; else + return args; + } + }, + publicip: { + label: 'label.public.ip' + }, + hostname: { + label: 'label.host' + }, + zonename: { + label: 'label.zone' + }, + state: { + label: 'label.vm.state', + converter: function (str) { + // For localization + return str; + }, + indicator: { + 'Running': 'on', + 'Stopped': 'off', + 'Error': 'off', + 'Destroyed': 'off' + } + }, + + agentstate: { + label: 'label.agent.state', + indicator: { + 'Up': 'on', + 'Down': 'off' + } + } + }, + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + + var selectedZoneObj = args.context.physicalResources[0]; + $.ajax({ + url: createURL("listSystemVms&zoneid=" + selectedZoneObj.id + "&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + dataType: "json", + async: true, + success: function (json) { + var items = json.listsystemvmsresponse.systemvm; + args.response.success({ + actionFilter: systemvmActionfilter, + data: items + }); + } + }); + }, + + detailView: { + name: 'label.system.vm.details', + actions: { + start: { + label: 'label.action.start.systemvm', + messages: { + confirm: function (args) { + return 'message.action.start.systemvm'; + }, + notification: function (args) { + return 'label.action.start.systemvm'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('startSystemVm&id=' + args.context.systemVMs[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.startsystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.systemvm; + }, + getActionFilter: function () { + return systemvmActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + stop: { + label: 'label.action.stop.systemvm', + messages: { + confirm: function (args) { + return 'message.action.stop.systemvm'; + }, + notification: function (args) { + return 'label.action.stop.systemvm'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('stopSystemVm&id=' + args.context.systemVMs[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.stopsystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.systemvm; + }, + getActionFilter: function () { + return systemvmActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + restart: { + label: 'label.action.reboot.systemvm', + messages: { + confirm: function (args) { + return 'message.action.reboot.systemvm'; + }, + notification: function (args) { + return 'label.action.reboot.systemvm'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('rebootSystemVm&id=' + args.context.systemVMs[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.rebootsystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.systemvm; + }, + getActionFilter: function () { + return systemvmActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + remove: { + label: 'label.action.destroy.systemvm', + messages: { + confirm: function (args) { + return 'message.action.destroy.systemvm'; + }, + notification: function (args) { + return 'label.action.destroy.systemvm'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('destroySystemVm&id=' + args.context.systemVMs[0].id), + dataType: 'json', + async: true, + success: function (json) { + var jid = json.destroysystemvmresponse.jobid; + args.response.success({ + _custom: { + getUpdatedItem: function () { + return { + state: 'Destroyed' + }; + }, + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + migrate: { + label: 'label.action.migrate.systemvm', + messages: { + notification: function (args) { + return 'label.action.migrate.systemvm'; + } + }, + createForm: { + title: 'label.action.migrate.systemvm', + desc: '', + fields: { + hostId: { + label: 'label.host', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL("findHostsForMigration&VirtualMachineId=" + args.context.systemVMs[0].id), + dataType: "json", + async: true, + success: function (json) { + var hostObjs = json.findhostsformigrationresponse.host; + var items =[]; + $(hostObjs).each(function () { + if (this.requiresStorageMotion == false) { + items.push({ + id: this.id, + description: (this.name + " (" + (this.suitableformigration ? "Suitable": "Not Suitable") + ")") + }); + } + }); + args.response.success({ + data: items + }); + } + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + } + } + }, + action: function (args) { + $.ajax({ + url: createURL("migrateSystemVm&hostid=" + args.data.hostId + "&virtualmachineid=" + args.context.systemVMs[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.migratesystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + //return json.queryasyncjobresultresponse.jobresult.systemvminstance; //not all properties returned in systemvminstance + $.ajax({ + url: createURL("listSystemVms&id=" + json.queryasyncjobresultresponse.jobresult.systemvm.id), + dataType: "json", + async: false, + success: function (json) { + var items = json.listsystemvmsresponse.systemvm; + if (items != null && items.length > 0) { + return items[0]; + } + } + }); + }, + getActionFilter: function () { + return systemvmActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + diagnostics: { + label: 'label.action.run.diagnostics', + messages: { + notification: function (args) { + return 'label.action.run.diagnostics'; + }, + complete: function(args) { + var exitcode = _l('message.diagnostics.exitcode'); + exitcode = exitcode.replace('var', args.exitcode); + var stderr = _l('message.diagnostics.stderr'); + stderr = stderr.replace('var', args.stderr); + var stdout = _l('message.diagnostics.stdout'); + stdout = stdout.replace('var', args.stdout); + var msg = "
    " + exitcode + "

    " + stderr + "

    " + stdout + "
    "; + return msg; + } + }, + createForm: { + title: 'label.action.run.diagnostics', + desc: '', + fields: { + type: { + label: 'label.run.diagnostics.type', + validation: { + required: true + }, + select: function (args) { + var items = []; + items.push({ + id: "ping", + description: "Ping" + }); + items.push({ + id: "traceroute", + description: "Traceroute" + }); + items.push({ + id: "arping", + description: "Arping" + }); + args.response.success({ + data: items + }); + } + }, + destination: { + label: 'label.run.diagnostics.destination', + validation: { + required: true + } + }, + extra: { + label: 'label.run.diagnostics.extra' + } + + } + }, + action: function (args) { + $.ajax({ + url: createURL("runDiagnostics&targetid=" + args.context.systemVMs[0].id + "&ipaddress=" + args.data.destination + "&type=" + args.data.type + "¶ms=" + args.data.extra), + dataType: "json", + async: true, + success: function(json) { + var jid = json.rundiagnosticsresponse.jobid; + args.response.success({ + _custom: { + jobId : jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.diagnostics; + + }, + getActionFilter: function(){ + return systemvmActionfilter; + } + } + + }); + } + }); //end ajax + }, + notification: { + poll: pollAsyncJobResult + } + }, + + retrieveDiagnostics: { + label: 'label.action.get.diagnostics', + messages: { + notification: function (args) { + return 'label.action.get.diagnostics'; + }, + complete: function(args) { + var url = args.url; + var htmlMsg = _l('message.download.diagnostics'); + var htmlMsg2 = htmlMsg.replace(/#/, url).replace(/00000/, url); + return htmlMsg2; + } + }, + createForm: { + title: 'label.action.get.diagnostics', + desc: 'label.get.diagnostics.desc', + fields: { + files: { + label: 'label.get.diagnostics.files' + } + } + }, + action: function (args) { + $.ajax({ + url: createURL("getDiagnosticsData&targetid=" + args.context.systemVMs[0].id + "&files=" + args.data.files), + dataType: "json", + async: true, + success: function(json) { + var jid = json.getdiagnosticsdataresponse.jobid; + args.response.success({ + _custom: { + jobId : jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.diagnostics; + + }, + getActionFilter: function(){ + return systemvmActionfilter; + } + } + + }); + } + }); //end ajax + }, + notification: { + poll: pollAsyncJobResult + } + }, + + scaleUp: { //*** Infrastructure > System VMs (consoleProxy or SSVM) > change service offering *** + label: 'label.change.service.offering', + createForm: { + title: 'label.change.service.offering', + desc: function (args) { + var description = ''; + var vmObj = args.jsonObj; + //if (vmObj.state == 'Running' && vmObj.hypervisor == 'VMware') { //needs to wait for API fix that will return hypervisor property + if (vmObj.state == 'Running') { + description = 'message.read.admin.guide.scaling.up'; + } + return description; + }, + fields: { + serviceOfferingId: { + label: 'label.compute.offering', + select: function (args) { + var data1 = { + issystem: 'true', + virtualmachineid: args.context.systemVMs[0].id + }; + if (args.context.systemVMs[0].systemvmtype == "secondarystoragevm") { + $.extend(data1, { + systemvmtype: 'secondarystoragevm' + }); + } + else if (args.context.systemVMs[0].systemvmtype == "consoleproxy") { + $.extend(data1, { + systemvmtype: 'consoleproxy' + }); + } + $.ajax({ + url: createURL('listServiceOfferings'), + data: data1, + success: function (json) { + var serviceofferings = json.listserviceofferingsresponse.serviceoffering; + var items =[]; + $(serviceofferings).each(function () { + if (this.id != args.context.systemVMs[0].serviceofferingid) { + items.push({ + id: this.id, + description: this.name + }); + } + }); + args.response.success({ + data: items + }); + } + }); + } + } + } + }, + + action: function (args) { + $.ajax({ + url: createURL("scaleSystemVm&id=" + args.context.systemVMs[0].id + "&serviceofferingid=" + args.data.serviceOfferingId), + dataType: "json", + async: true, + success: function (json) { + var jid = json.changeserviceforsystemvmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.systemvm; + }, + getActionFilter: function () { + return vmActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.scale.up.system.vm'; + }, + notification: function (args) { + + return 'label.system.vm.scaled.up'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + viewConsole: { + label: 'label.view.console', + action: { + externalLink: { + url: function (args) { + return clientConsoleUrl + '?cmd=access&vm=' + args.context.systemVMs[0].id; + }, + title: function (args) { + return args.context.systemVMs[0].id.substr(0, 8); + //title in window.open() can't have space nor longer than 8 characters. Otherwise, IE browser will have error. + }, + width: 820, + height: 640 + } + } + } + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + id: { + label: 'label.id' + }, + state: { + label: 'label.state' + }, + systemvmtype: { + label: 'label.type', + converter: function (args) { + if (args == "consoleproxy") + return "Console Proxy VM"; else if (args == "secondarystoragevm") + return "Secondary Storage VM"; else + return args; + } + }, + zonename: { + label: 'label.zone' + }, + publicip: { + label: 'label.public.ip' + }, + privateip: { + label: 'label.private.ip' + }, + linklocalip: { + label: 'label.linklocal.ip' + }, + hostname: { + label: 'label.host' + }, + gateway: { + label: 'label.gateway' + }, + created: { + label: 'label.created', + converter: cloudStack.converters.toLocalDate + }, + activeviewersessions: { + label: 'label.active.sessions' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listSystemVms&id=" + args.context.systemVMs[0].id), + dataType: "json", + async: true, + success: function (json) { + args.response.success({ + actionFilter: systemvmActionfilter, + data: json.listsystemvmsresponse.systemvm[0] + }); + } + }); + } + } + } + } + } + }, + // netscaler devices listView + netscalerDevices: { + id: 'netscalerDevices', + title: 'label.devices', + listView: { + id: 'netscalerDevices', + fields: { + ipaddress: { + label: 'label.ip.address' + }, + lbdevicestate: { + converter: function (str) { + // For localization + return str; + }, + label: 'label.status' + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL("listNetscalerLoadBalancers&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + data: { + page: args.page, + pageSize: pageSize + }, + dataType: "json", + async: false, + success: function (json) { + var items = json.listnetscalerloadbalancerresponse.netscalerloadbalancer; + args.response.success({ + data: items + }); + } + }); + }, + actions: { + add: { + label: 'label.add.netScaler.device', + createForm: { + title: 'label.add.netScaler.device', + preFilter: cloudStack.preFilter.addLoadBalancerDevice, + fields: { + ip: { + label: 'label.ip.address' + }, + username: { + label: 'label.username' + }, + password: { + label: 'label.password', + isPassword: true + }, + networkdevicetype: { + label: 'label.type', + select: function (args) { + var items =[]; + items.push({ + id: "NetscalerMPXLoadBalancer", + description: "NetScaler MPX LoadBalancer" + }); + items.push({ + id: "NetscalerVPXLoadBalancer", + description: "NetScaler VPX LoadBalancer" + }); + items.push({ + id: "NetscalerSDXLoadBalancer", + description: "NetScaler SDX LoadBalancer" + }); + args.response.success({ + data: items + }); + } + }, + publicinterface: { + label: 'label.public.interface' + }, + privateinterface: { + label: 'label.private.interface' + }, + + gslbprovider: { + label: 'label.gslb.service', + isBoolean: true, + isChecked: false + }, + gslbproviderpublicip: { + label: 'label.gslb.service.public.ip' + }, + gslbproviderprivateip: { + label: 'label.gslb.service.private.ip' + }, + + numretries: { + label: 'label.numretries', + defaultValue: '2' + }, + /* inline: { + label: 'Mode', + select: function(args) { + var items = []; + items.push({id: "false", description: "side by side"}); + items.push({id: "true", description: "inline"}); + args.response.success({data: items}); + } + },*/ + dedicated: { + label: 'label.dedicated', + isBoolean: true, + isChecked: false + }, + capacity: { + label: 'label.capacity', + validation: { + required: false, + number: true + } + } + } + }, + action: function (args) { + if (nspMap[ "netscaler"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=Netscaler&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addNetscalerProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addNetscalerProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "netscaler"] = result.jobresult.networkserviceprovider; + addExternalLoadBalancer(args, selectedPhysicalNetworkObj, "addNetscalerLoadBalancer", "addnetscalerloadbalancerresponse", "netscalerloadbalancer"); + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=Netscaler failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=Netscaler failed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else { + addExternalLoadBalancer(args, selectedPhysicalNetworkObj, "addNetscalerLoadBalancer", "addnetscalerloadbalancerresponse", "netscalerloadbalancer"); + } + }, + messages: { + notification: function (args) { + return 'label.add.netScaler.device'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + detailView: { + name: 'label.netscaler.details', + actions: { + 'remove': { + label: 'label.delete.NetScaler', + messages: { + confirm: function (args) { + return 'message.confirm.delete.NetScaler'; + }, + notification: function (args) { + return 'label.delete.NetScaler'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("deleteNetscalerLoadBalancer&lbdeviceid=" + args.context.netscalerDevices[0].lbdeviceid), + dataType: "json", + async: true, + success: function (json) { + var jid = json.deletenetscalerloadbalancerresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + }, + + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + lbdeviceid: { + label: 'label.id' + }, + ipaddress: { + label: 'label.ip.address' + }, + lbdevicestate: { + label: 'label.status' + }, + lbdevicename: { + label: 'label.type' + }, + lbdevicecapacity: { + label: 'label.capacity' + }, + lbdevicededicated: { + label: 'label.dedicated', + converter: cloudStack.converters.toBooleanText + }, + gslbprovider: { + label: 'label.gslb.service', + converter: cloudStack.converters.toBooleanText + }, + gslbproviderpublicip: { + label: 'label.gslb.service.public.ip' + }, + gslbproviderprivateip: { + label: 'label.gslb.service.private.ip' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listNetscalerLoadBalancers&lbdeviceid=" + args.context.netscalerDevices[0].lbdeviceid), + dataType: "json", + async: true, + success: function (json) { + var item = json.listnetscalerloadbalancerresponse.netscalerloadbalancer[0]; + args.response.success({ + data: item + }); + } + }); + } + } + } + } + } + }, + + // Baremetal DHCP devices listView + BaremetalDhcpDevices: { + id: 'BaremetalDhcpDevices', + title: 'label.baremetal.dhcp.devices', + listView: { + id: 'BaremetalDhcpDevices', + fields: { + url: { + label: 'label.url' + } + }, + actions: { + add: { + label: 'label.add.baremetal.dhcp.device', + createForm: { + title: 'label.add.baremetal.dhcp.device', + fields: { + url: { + label: 'label.url', + validation: { + required: true + } + }, + username: { + label: 'label.username', + validation: { + required: true + } + }, + password: { + label: 'label.password', + isPassword: true, + validation: { + required: true + } + } + } + }, + action: function (args) { + addBaremetalDhcpDeviceFn(args); + }, + messages: { + notification: function (args) { + return 'label.add.baremetal.dhcp.device'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL('listBaremetalDhcp'), + data: { + physicalnetworkid: selectedPhysicalNetworkObj.id, + page: args.page, + pageSize: pageSize + }, + dataType: "json", + async: false, + success: function (json) { + var items = json.listbaremetaldhcpresponse.baremetaldhcp; + args.response.success({ + data: items + }); + } + }); + } + } + }, + + // Baremetal PXE devices listView + BaremetalPxeDevices: { + id: 'BaremetalPxeDevices', + title: 'label.baremetal.pxe.devices', + listView: { + id: 'BaremetalPxeDevices', + fields: { + url: { + label: 'label.url' + } + }, + actions: { + add: { + label: 'label.baremetal.pxe.device', + createForm: { + title: 'label.baremetal.pxe.device', + fields: { + url: { + label: 'label.url', + validation: { + required: true + } + }, + username: { + label: 'label.username', + validation: { + required: true + } + }, + password: { + label: 'label.password', + isPassword: true, + validation: { + required: true + } + }, + tftpdir: { + label: 'label.tftp.root.directory', + validation: { + required: true + } + } + } + }, + action: function (args) { + addBaremetalPxeDeviceFn(args); + }, + messages: { + notification: function (args) { + return 'label.baremetal.pxe.device'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL('listBaremetalPxeServers'), + data: { + physicalnetworkid: selectedPhysicalNetworkObj.id, + page: args.page, + pageSize: pageSize + }, + dataType: "json", + async: false, + success: function (json) { + var items = json.listbaremetalpxeserversresponse.baremetalpxeserver; + args.response.success({ + data: items + }); + } + }); + } + } + }, + + // F5 devices listView + f5Devices: { + id: 'f5Devices', + title: 'label.devices', + listView: { + id: 'f5Devices', + fields: { + ipaddress: { + label: 'label.ip.address' + }, + lbdevicestate: { + converter: function (str) { + // For localization + return str; + }, + label: 'label.status' + } + }, + actions: { + add: { + label: 'label.add.F5.device', + createForm: { + title: 'label.add.F5.device', + preFilter: cloudStack.preFilter.addLoadBalancerDevice, + fields: { + ip: { + label: 'label.ip.address' + }, + username: { + label: 'label.username' + }, + password: { + label: 'label.password', + isPassword: true + }, + networkdevicetype: { + label: 'label.type', + select: function (args) { + var items =[]; + items.push({ + id: "F5BigIpLoadBalancer", + description: "F5 Big Ip Load Balancer" + }); + args.response.success({ + data: items + }); + } + }, + publicinterface: { + label: 'label.public.interface' + }, + privateinterface: { + label: 'label.private.interface' + }, + numretries: { + label: 'label.numretries', + defaultValue: '2' + }, + //Inline Mode has been moved from Add F5 Device to Create Network Offering (both backend and UI) + /* + inline: { + label: 'Mode', + select: function(args) { + var items = []; + items.push({id: "false", description: "side by side"}); + items.push({id: "true", description: "inline"}); + args.response.success({data: items}); + } + }, + */ + dedicated: { + label: 'label.dedicated', + isBoolean: true, + isChecked: false + }, + capacity: { + label: 'label.capacity', + validation: { + required: false, + number: true + } + } + } + }, + action: function (args) { + if (nspMap[ "f5"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=F5BigIp&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addF5ProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addF5ProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "f5"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + addExternalLoadBalancer(args, selectedPhysicalNetworkObj, "addF5LoadBalancer", "addf5bigiploadbalancerresponse", "f5loadbalancer"); + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=F5BigIp failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=F5BigIpfailed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else { + addExternalLoadBalancer(args, selectedPhysicalNetworkObj, "addF5LoadBalancer", "addf5bigiploadbalancerresponse", "f5loadbalancer"); + } + }, + messages: { + notification: function (args) { + return 'label.addes.new.f5'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL("listF5LoadBalancers&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + data: { + page: args.page, + pageSize: pageSize + }, + dataType: "json", + async: false, + success: function (json) { + var items = json.listf5loadbalancerresponse.f5loadbalancer; + args.response.success({ + data: items + }); + } + }); + }, + detailView: { + name: 'label.f5.details', + actions: { + 'remove': { + label: 'label.delete.F5', + messages: { + confirm: function (args) { + return 'message.confirm.delete.F5'; + }, + notification: function (args) { + return 'label.delete.F5'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("deleteF5LoadBalancer&lbdeviceid=" + args.context.f5Devices[0].lbdeviceid), + dataType: "json", + async: true, + success: function (json) { + var jid = json.deletef5loadbalancerresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + lbdeviceid: { + label: 'label.id' + }, + ipaddress: { + label: 'label.ip.address' + }, + lbdevicestate: { + label: 'label.status' + }, + lbdevicename: { + label: 'label.type' + }, + lbdevicecapacity: { + label: 'label.capacity' + }, + lbdevicededicated: { + label: 'label.dedicated', + converter: cloudStack.converters.toBooleanText + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listF5LoadBalancers&lbdeviceid=" + args.context.f5Devices[0].lbdeviceid), + dataType: "json", + async: true, + success: function (json) { + var item = json.listf5loadbalancerresponse.f5loadbalancer[0]; + args.response.success({ + data: item + }); + } + }); + } + } + } + } + } + }, + + //SRX devices listView + srxDevices: { + id: 'srxDevices', + title: 'label.devices', + listView: { + id: 'srxDevices', + fields: { + ipaddress: { + label: 'label.ip.address' + }, + fwdevicestate: { + label: 'label.status' + }, + fwdevicename: { + label: 'label.type' + } + }, + actions: { + add: { + label: 'label.add.SRX.device', + createForm: { + title: 'label.add.SRX.device', + fields: { + ip: { + label: 'label.ip.address' + }, + username: { + label: 'label.username' + }, + password: { + label: 'label.password', + isPassword: true + }, + networkdevicetype: { + label: 'label.type', + select: function (args) { + var items =[]; + items.push({ + id: "JuniperSRXFirewall", + description: "Juniper SRX Firewall" + }); + args.response.success({ + data: items + }); + } + }, + publicinterface: { + label: 'label.public.interface' + }, + privateinterface: { + label: 'label.private.interface' + }, + usageinterface: { + label: 'label.usage.interface' + }, + numretries: { + label: 'label.numretries', + defaultValue: '2' + }, + timeout: { + label: 'label.timeout', + defaultValue: '300' + }, + // inline: { + // label: 'Mode', + // select: function(args) { + // var items = []; + // items.push({id: "false", description: "side by side"}); + // items.push({id: "true", description: "inline"}); + // args.response.success({data: items}); + // } + // }, + publicnetwork: { + label: 'label.public.network', + defaultValue: 'untrusted', + isDisabled: true + }, + privatenetwork: { + label: 'label.private.network', + defaultValue: 'trusted', + isDisabled: true + }, + capacity: { + label: 'label.capacity', + validation: { + required: false, + number: true + } + }, + dedicated: { + label: 'label.dedicated', + isBoolean: true, + isChecked: false + } + } + }, + action: function (args) { + if (nspMap[ "srx"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=JuniperSRX&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addJuniperSRXProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addJuniperSRXProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "srx"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + addExternalFirewall(args, selectedPhysicalNetworkObj, "addSrxFirewall", "addsrxfirewallresponse", "srxfirewall"); + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=JuniperSRX failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=JuniperSRX failed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else { + addExternalFirewall(args, selectedPhysicalNetworkObj, "addSrxFirewall", "addsrxfirewallresponse", "srxfirewall"); + } + }, + messages: { + notification: function (args) { + return 'label.add.SRX.device'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL("listSrxFirewalls&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + data: { + page: args.page, + pageSize: pageSize + }, + dataType: "json", + async: false, + success: function (json) { + var items = json.listsrxfirewallresponse.srxfirewall; + args.response.success({ + data: items + }); + } + }); + }, + detailView: { + name: 'label.srx.details', + actions: { + 'remove': { + label: 'label.delete.SRX', + messages: { + confirm: function (args) { + return 'message.confirm.delete.SRX'; + }, + notification: function (args) { + return 'label.delete.SRX'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("deleteSrxFirewall&fwdeviceid=" + args.context.srxDevices[0].fwdeviceid), + dataType: "json", + async: true, + success: function (json) { + var jid = json.deletesrxfirewallresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + fwdeviceid: { + label: 'label.id' + }, + ipaddress: { + label: 'label.ip.address' + }, + fwdevicestate: { + label: 'label.status' + }, + fwdevicename: { + label: 'label.type' + }, + fwdevicecapacity: { + label: 'label.capacity' + }, + timeout: { + label: 'label.timeout' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listSrxFirewalls&fwdeviceid=" + args.context.srxDevices[0].fwdeviceid), + dataType: "json", + async: true, + success: function (json) { + var item = json.listsrxfirewallresponse.srxfirewall[0]; + args.response.success({ + data: item + }); + } + }); + } + } + } + } + } + }, + + //Palo Alto devices listView + paDevices: { + id: 'paDevices', + title: 'label.devices', + listView: { + id: 'paDevices', + fields: { + ipaddress: { + label: 'label.ip.address' + }, + fwdevicestate: { + label: 'label.status' + }, + fwdevicename: { + label: 'label.type' + } + }, + actions: { + add: { + label: 'label.add.PA.device', + createForm: { + title: 'label.add.PA.device', + fields: { + ip: { + label: 'label.ip.address' + }, + username: { + label: 'label.username' + }, + password: { + label: 'label.password', + isPassword: true + }, + networkdevicetype: { + label: 'label.type', + select: function (args) { + var items =[]; + items.push({ + id: "PaloAltoFirewall", + description: "Palo Alto Firewall" + }); + args.response.success({ + data: items + }); + } + }, + publicinterface: { + label: 'label.public.interface' + }, + privateinterface: { + label: 'label.private.interface' + }, + //usageinterface: { + // label: 'label.usage.interface' + //}, + numretries: { + label: 'label.numretries', + defaultValue: '2' + }, + timeout: { + label: 'label.timeout', + defaultValue: '300' + }, + // inline: { + // label: 'Mode', + // select: function(args) { + // var items = []; + // items.push({id: "false", description: "side by side"}); + // items.push({id: "true", description: "inline"}); + // args.response.success({data: items}); + // } + // }, + publicnetwork: { + label: 'label.public.network', + defaultValue: 'untrust' + }, + privatenetwork: { + label: 'label.private.network', + defaultValue: 'trust' + }, + pavr: { + label: 'label.virtual.router' + }, + patp: { + label: 'label.PA.threat.profile' + }, + palp: { + label: 'label.PA.log.profile' + }, + capacity: { + label: 'label.capacity', + validation: { + required: false, + number: true + } + }, + dedicated: { + label: 'label.dedicated', + isBoolean: true, + isChecked: false + } + } + }, + action: function (args) { + if (nspMap[ "pa"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=PaloAlto&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addPaloAltoProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addPaloAltoProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "pa"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + addExternalFirewall(args, selectedPhysicalNetworkObj, "addPaloAltoFirewall", "addpaloaltofirewallresponse", "pafirewall"); + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=Palo Alto failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=Palo Alto failed. Error: " + errorMsg); + } + }); + }, + 3000); + } + }); + } else { + addExternalFirewall(args, selectedPhysicalNetworkObj, "addPaloAltoFirewall", "addpaloaltofirewallresponse", "pafirewall"); + } + }, + messages: { + notification: function (args) { + return 'label.add.PA.device'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL("listPaloAltoFirewalls&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + data: { + page: args.page, + pageSize: pageSize + }, + dataType: "json", + async: false, + success: function (json) { + var items = json.listpaloaltofirewallresponse.paloaltofirewall; + args.response.success({ + data: items + }); + } + }); + }, + detailView: { + name: 'label.palo.alto.details', + actions: { + 'remove': { + label: 'label.delete.PA', + messages: { + confirm: function (args) { + return 'message.confirm.delete.PA'; + }, + notification: function (args) { + return 'label.delete.PA'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("deletePaloAltoFirewall&fwdeviceid=" + args.context.paDevices[0].fwdeviceid), + dataType: "json", + async: true, + success: function (json) { + var jid = json.deletepaloaltofirewallresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + fwdeviceid: { + label: 'label.id' + }, + ipaddress: { + label: 'label.ip.address' + }, + fwdevicestate: { + label: 'label.status' + }, + fwdevicename: { + label: 'label.type' + }, + fwdevicecapacity: { + label: 'label.capacity' + }, + timeout: { + label: 'label.timeout' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listPaloAltoFirewalls&fwdeviceid=" + args.context.paDevices[0].fwdeviceid), + dataType: "json", + async: true, + success: function (json) { + var item = json.listpaloaltofirewallresponse.paloaltofirewall[0]; + args.response.success({ + data: item + }); + } + }); + } + } + } + } + } + }, + + // FIXME convert to nicira detailview + // NiciraNvp devices listView + niciraNvpDevices: { + id: 'niciraNvpDevices', + title: 'label.devices', + listView: { + id: 'niciraNvpDevices', + fields: { + hostname: { + label: 'label.nicira.controller.address' + }, + transportzoneuuid: { + label: 'label.nicira.transportzoneuuid' + }, + l3gatewayserviceuuid: { + label: 'label.nicira.l3gatewayserviceuuid' + }, + l2gatewayserviceuuid: { + label: 'label.nicira.l2gatewayserviceuuid' + } + }, + actions: { + add: { + label: 'label.add.NiciraNvp.device', + createForm: { + title: 'label.add.NiciraNvp.device', + preFilter: function (args) { + }, + // TODO What is this? + fields: { + host: { + label: 'label.ip.address' + }, + username: { + label: 'label.username' + }, + password: { + label: 'label.password', + isPassword: true + }, + numretries: { + label: 'label.numretries', + defaultValue: '2' + }, + transportzoneuuid: { + label: 'label.nicira.transportzoneuuid' + }, + l3gatewayserviceuuid: { + label: 'label.nicira.l3gatewayserviceuuid' + }, + l2gatewayserviceuuid: { + label: 'label.nicira.l2gatewayserviceuuid' + } + } + }, + action: function (args) { + if (nspMap[ "niciraNvp"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=NiciraNvp&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addNiciraNvpProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; // Job has not completed + } else { + clearInterval(addNiciraNvpProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "niciraNvp"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + addNiciraNvpDevice(args, selectedPhysicalNetworkObj, "addNiciraNvpDevice", "addniciranvpdeviceresponse", "niciranvpdevice") + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=NiciraNvp failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=NiciraNvp failed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else { + addNiciraNvpDevice(args, selectedPhysicalNetworkObj, "addNiciraNvpDevice", "addniciranvpdeviceresponse", "niciranvpdevice") + } + }, + + messages: { + notification: function (args) { + return 'label.added.nicira.nvp.controller'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL("listNiciraNvpDevices&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + data: { + page: args.page, + pageSize: pageSize + }, + dataType: "json", + async: false, + success: function (json) { + var items = json.listniciranvpdeviceresponse.niciranvpdevice; + args.response.success({ + data: items + }); + } + }); + }, + detailView: { + name: 'label.nicira.nvp.details', + actions: { + 'remove': { + label: 'label.delete.NiciaNvp', + messages: { + confirm: function (args) { + return 'message.confirm.delete.NiciraNvp'; + }, + notification: function (args) { + return 'label.delete.NiciraNvp'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("deleteNiciraNvpDevice&nvpdeviceid=" + args.context.niciraNvpDevices[0].nvpdeviceid), + dataType: "json", + async: true, + success: function (json) { + var jid = json.deleteniciranvpdeviceresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + nvpdeviceid: { + label: 'label.id' + }, + hostname: { + label: 'label.ip.address' + }, + transportzoneuuid: { + label: 'label.nicira.transportzoneuuid' + }, + l3gatewayserviceuuid: { + label: 'label.nicira.l3gatewayserviceuuid' + }, + l2gatewayserviceuuid: { + label: 'label.nicira.l2gatewayserviceuuid' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listNiciraNvpDevices&nvpdeviceid=" + args.context.niciraNvpDevices[0].nvpdeviceid), + dataType: "json", + async: true, + success: function (json) { + var item = json.listniciranvpdeviceresponse.niciranvpdevice[0]; + args.response.success({ + data: item + }); + } + }); + } + } + } + } + } + }, + // BrocadeVcs devices listView + brocadeVcsDevices: { + id: 'brocadeVcsDevices', + title: 'label.devices', + listView: { + id: 'brocadeVcsDevices', + fields: { + hostname: { + label: 'label.brocade.vcs.address' + } + }, + actions: { + add: { + label: 'label.add.BrocadeVcs.device', + createForm: { + title: 'label.add.BrocadeVcs.device', + preFilter: function (args) { + }, + // TODO What is this? + fields: { + host: { + label: 'label.ip.address' + }, + username: { + label: 'label.username' + }, + password: { + label: 'label.password', + isPassword: true + } + } + }, + action: function (args) { + if (nspMap[ "brocadeVcs"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=BrocadeVcs&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addBrocadeVcsProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; // Job has not completed + } else { + clearInterval(addBrocadeVcsProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "brocadeVcs"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + addBrocadeVcsDevice(args, selectedPhysicalNetworkObj, "addBrocadeVcsDevice", "addbrocadevcsdeviceresponse", "brocadevcsdevice") + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=BrocadeVcs failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=BrocadeVcs failed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else { + addBrocadeVcsDevice(args, selectedPhysicalNetworkObj, "addBrocadeVcsDevice", "addbrocadevcsdeviceresponse", "brocadevcsdevice") + } + }, + messages: { + notification: function (args) { + return 'label.added.brocade.vcs.switch'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL("listBrocadeVcsDevices&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + data: { + page: args.page, + pageSize: pageSize + }, + dataType: "json", + async: false, + success: function (json) { + var items = json.listbrocadevcsdeviceresponse.brocadevcsdevice; + args.response.success({ + data: items + }); + } + }); + }, + detailView: { + name: 'label.brocade.vcs.details', + actions: { + 'remove': { + label: 'label.delete.BrocadeVcs', + messages: { + confirm: function (args) { + return 'message.confirm.delete.BrocadeVcs'; + }, + notification: function (args) { + return 'label.delete.BrocadeVcs'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("deleteBrocadeVcsDevice&vcsdeviceid=" + args.context.brocadeVcsDevices[0].vcsdeviceid), + dataType: "json", + async: true, + success: function (json) { + var jid = json.deletebrocadevcsdeviceresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + vcsdeviceid: { + label: 'label.id' + }, + hostname: { + label: 'label.ip.address' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listBrocadeVcsDevices&vcsdeviceid=" + args.context.brocadeVcsDevices[0].vcsdeviceid), + dataType: "json", + async: true, + success: function (json) { + var item = json.listbrocadevcsdeviceresponse.brocadevcsdevice[0]; + args.response.success({ + data: item + }); + } + }); + } + } + } + } + } + }, + bigswitchBcfDevices: { + id: 'bigswitchBcfDevices', + title: 'label.devices', + listView: { + id: 'bigswitchBcfDevices', + fields: { + hostname: { + label: 'label.bigswitch.controller.address' + } + }, + actions: { + add: { + label: 'label.add.BigSwitchBcf.device', + createForm: { + title: 'label.add.BigSwitchBcf.device', + preFilter: function (args) { + }, + fields: { + host: { + label: 'label.ip.address', + validation: { + required: true + } + }, + username: { + label: 'label.username', + validation: { + required: true + } + }, + password: { + label: 'label.password', + isPassword: true, + validation: { + required: true + } + }, + nat: { + label: 'label.bigswitch.bcf.nat', + isBoolean: true, + isChecked: false + }, + numretries: { + label: 'label.numretries', + defaultValue: '2' + } + } + }, + action: function (args) { + if (nspMap[ "bigswitchBcf"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=BigSwitchBcf&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addBigSwitchBcfProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; + } else { + clearInterval(addBigSwitchBcfProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "bigswitchBcf"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + addBigSwitchBcfDevice(args, selectedPhysicalNetworkObj, "addBigSwitchBcfDevice", "addbigswitchbcfdeviceresponse", "bigswitchbcfdevice") + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=BigSwitchBcf failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=BigSwitchBcf failed. Error: " + errorMsg); + } + }); + }, + 3000); + } + }); + } else { + addBigSwitchBcfDevice(args, selectedPhysicalNetworkObj, "addBigSwitchBcfDevice", "addbigswitchbcfdeviceresponse", "bigswitchbcfdevice") + } + }, + + messages: { + notification: function (args) { + return 'label.added.new.bigswitch.bcf.controller'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL("listBigSwitchBcfDevices&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + data: { + page: args.page, + pageSize: pageSize + }, + dataType: "json", + async: false, + success: function (json) { + var items = json.listbigswitchbcfdeviceresponse.bigswitchbcfdevice; + args.response.success({ + data: items + }); + } + }); + }, + detailView: { + name: 'label.bigswitch.bcf.details', + actions: { + 'remove': { + label: 'label.delete.BigSwitchBcf', + messages: { + confirm: function (args) { + return 'message.confirm.delete.BigSwitchBcf'; + }, + notification: function (args) { + return 'label.delete.BigSwitchBcf'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("deleteBigSwitchBcfDevice&bcfdeviceid=" + args.context.bigswitchBcfDevices[0].bcfdeviceid), + dataType: "json", + async: true, + success: function (json) { + var jid = json.deletebigswitchbcfdeviceresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + bcfdeviceid: { + label: 'label.id' + }, + hostname: { + label: 'label.host.name' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listBigSwitchBcfDevices&bcfdeviceid=" + args.context.bigswitchBcfDevices[0].bcfdeviceid), + dataType: "json", + async: true, + success: function (json) { + var item = json.listbigswitchbcfdeviceresponse.bigswitchbcfdevice[0]; + args.response.success({ + data: item + }); + } + }); + } + } + } + } + } + }, + pods: { + title: 'label.pods', + listView: { + id: 'pods', + section: 'pods', + multiSelect: true, + fields: { + name: { + label: 'label.name' + }, + gateway: { + label: 'label.gateway' + }, + netmask: { + label: 'label.netmask' + }, + zonename: { + label: 'label.zone' + }, + allocationstate: { + converter: function (str) { + // For localization + return str; + }, + label: 'label.allocation.state', + indicator: { + 'Enabled': 'on', + 'Disabled': 'off' + } + } + }, + + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + + $.ajax({ + url: createURL("listPods&zoneid=" + args.context.zones[0].id + "&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + dataType: "json", + async: true, + success: function (json) { + var items = json.listpodsresponse.pod; + args.response.success({ + actionFilter: podActionfilter, + data: items + }); + } + }); + }, + + actions: { + add: { + label: 'label.add.pod', + + createForm: { + title: 'label.add.pod', + fields: { + zoneid: { + label: 'label.zone', + docID: 'helpPodZone', + validation: { + required: true + }, + select: function (args) { + var data = args.context.zones ? { + id: args.context.zones[0].id + }: {}; + + $.ajax({ + url: createURL('listZones'), + data: data, + success: function (json) { + var zones = json.listzonesresponse.zone ? json.listzonesresponse.zone:[]; + + args.response.success({ + data: $.map(zones, function (zone) { + return { + id: zone.id, + description: zone.name + }; + }) + }); + } + }); + } + }, + podname: { + label: 'label.pod.name', + docID: 'helpPodName', + validation: { + required: true + } + }, + reservedSystemGateway: { + label: 'label.reserved.system.gateway', + docID: 'helpPodGateway', + validation: { + required: true + } + }, + reservedSystemNetmask: { + label: 'label.reserved.system.netmask', + docID: 'helpPodNetmask', + validation: { + required: true + } + }, + reservedSystemStartIp: { + label: 'label.start.reserved.system.IP', + docID: 'helpPodStartIP', + validation: { + required: true + } + }, + reservedSystemEndIp: { + label: 'label.end.reserved.system.IP', + docID: 'helpPodEndIP', + validation: { + required: false + } + }, + + isDedicated: { + label: 'label.dedicate', + isBoolean: true, + isChecked: false, + docID: 'helpDedicateResource' + }, + + domainId: { + label: 'label.domain', + isHidden: true, + validation: { + required: true + }, + dependsOn: 'isDedicated', + select: function (args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function (json) { + var domainObjs = json.listdomainsresponse.domain; + var items =[]; + + $(domainObjs).each(function () { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + + args.response.success({ + data: items + }); + } + }); + } + }, + + accountId: { + label: 'label.account', + isHidden: true, + dependsOn: 'isDedicated', + docID: 'helpAccountForDedication', + validation: { + required: false + } + } + } + }, + + action: function (args) { + var array1 =[]; + var appendData = args.data.append ? args.data.append: { + }; + + array1.push("&zoneId=" + args.data.zoneid); + array1.push("&name=" + encodeURIComponent(args.data.podname)); + array1.push("&gateway=" + encodeURIComponent(args.data.reservedSystemGateway)); + array1.push("&netmask=" + encodeURIComponent(args.data.reservedSystemNetmask)); + array1.push("&startIp=" + encodeURIComponent(args.data.reservedSystemStartIp)); + + var endip = args.data.reservedSystemEndIp; //optional + if (endip != null && endip.length > 0) + array1.push("&endIp=" + encodeURIComponent(endip)); + var podId = null; + $.ajax({ + url: createURL("createPod" + array1.join("")), + data: appendData, + dataType: "json", + success: function (json) { + var item = json.createpodresponse.pod; + podId = json.createpodresponse.pod.id; + + //EXPLICIT DEDICATION + if (args.$form.find('.form-item[rel=isDedicated]').find('input[type=checkbox]').is(':Checked') == true) { + var array2 =[]; + if (args.data.accountId != "") + array2.push("&account=" + encodeURIComponent(args.data.accountId)); + + if (podId != null) { + $.ajax({ + url: createURL("dedicatePod&podId=" + podId + "&domainId=" + args.data.domainId + array2.join("")), + dataType: "json", + success: function (json) { + var jid = json.dedicatepodresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + }, + notification: { + poll: pollAsyncJobResult, + interval: 4500, + desc: "Dedicate Pod" + }, + + data: item + }); + }, + + error: function (json) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + } + } + args.response.success({ + data: item + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + }, + + notification: { + poll: function (args) { + args.complete({ + actionFilter: podActionfilter + }); + } + }, + + messages: { + notification: function (args) { + return 'label.add.pod'; + } + } + }, + startRollingMaintenance: rollingMaintenanceAction({ listView: true, entity: 'pods' }) + }, + + detailView: { + viewAll: { + path: '_zone.clusters', + label: 'label.clusters' + }, + tabFilter: function (args) { + var hiddenTabs =[]; + if (selectedZoneObj.networktype == "Basic") { + //basic-mode network (pod-wide VLAN) + //$("#tab_ipallocation, #add_iprange_button, #tab_network_device, #add_network_device_button").show(); + } else if (selectedZoneObj.networktype == "Advanced") { + //advanced-mode network (zone-wide VLAN) + //$("#tab_ipallocation, #add_iprange_button, #tab_network_device, #add_network_device_button").hide(); + hiddenTabs.push("ipAllocations"); + //hiddenTabs.push("networkDevices"); //network devices tab is moved out of pod page at 3.0 UI. It will go to new network page. + } + return hiddenTabs; + }, + actions: { + startRollingMaintenance: { + label: 'label.start.rolling.maintenance', + textLabel: 'label.start.rolling.maintenance', + messages: { + notification: function (args) { + return 'label.start.rolling.maintenance'; + } + }, + createForm: { + title: 'label.start.rolling.maintenance', + fields: { + timeout: { + label: 'label.timeout', + }, + force: { + isBoolean: true, + label: 'label.start.rolling.maintenance.force' + }, + payload: { + label: 'label.start.rolling.maintenance.payload' + } + } + }, + action: function (args) { + var data = { + podids: args.context.pods[0].id, + force: args.data.force, + timeout: args.data.timeout, + payload: args.data.payload + }; + $.ajax({ + url: createURL("startRollingMaintenance"), + dataType: "json", + data: data, + async: true, + success: function (json) { + var item = json.rollingmaintenance; + args.response.success({ + actionFilter: zoneActionfilter, + data: item + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + edit: { + label: 'label.edit', + action: function (args) { + var array1 =[]; + + array1.push("&name=" + encodeURIComponent(args.data.name)); + array1.push("&netmask=" + encodeURIComponent(args.data.netmask)); + + if (args.data.gateway != null && args.data.gateway.length > 0) + array1.push("&gateway=" + encodeURIComponent(args.data.gateway)); + + $.ajax({ + url: createURL("updatePod&id=" + args.context.pods[0].id + array1.join("")), + dataType: "json", + success: function (json) { + var item = json.updatepodresponse.pod; + args.response.success({ + actionFilter: podActionfilter, + data: item + }); + }, + error: function (data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + } + }, + + enable: { + label: 'label.action.enable.pod', + messages: { + confirm: function (args) { + return 'message.action.enable.pod'; + }, + notification: function (args) { + return 'label.action.enable.pod'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("updatePod&id=" + args.context.pods[0].id + "&allocationstate=Enabled"), + dataType: "json", + async: true, + success: function (json) { + var item = json.updatepodresponse.pod; + args.response.success({ + actionFilter: podActionfilter, + data: item + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + dedicate: { + label: 'label.dedicate.pod', + messages: { + confirm: function (args) { + return 'message.confirm.dedicate.pod.domain.account'; + }, + notification: function (args) { + return 'label.pod.dedicated'; + } + }, + createForm: { + title: 'label.dedicate.pod', + fields: { + domainId: { + label: 'label.domain', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function (json) { + var domainObjs = json.listdomainsresponse.domain; + var items =[]; + + $(domainObjs).each(function () { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + + args.response.success({ + data: items + }); + } + }); + } + }, + accountId: { + label: 'label.account', + docID: 'helpAccountForDedication', + validation: { + required: false + } + } + } + }, + action: function (args) { + //EXPLICIT DEDICATION + var array2 =[]; + if (args.data.accountId != "") + array2.push("&account=" + encodeURIComponent(args.data.accountId)); + + $.ajax({ + url: createURL("dedicatePod&podId=" + + args.context.pods[0].id + + "&domainId=" + args.data.domainId + array2.join("")), + dataType: "json", + success: function (json) { + var jid = json.dedicatepodresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return podActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + release: { + label: 'label.release.dedicated.pod', + messages: { + confirm: function (args) { + return 'message.confirm.release.dedicated.pod'; + }, + notification: function (args) { + return 'message.pod.dedication.released'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("releaseDedicatedPod&podid=" + args.context.pods[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.releasededicatedpodresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return podActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + + disable: { + label: 'label.action.disable.pod', + messages: { + confirm: function (args) { + return 'message.action.disable.pod'; + }, + notification: function (args) { + return 'label.action.disable.pod'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("updatePod&id=" + args.context.pods[0].id + "&allocationstate=Disabled"), + dataType: "json", + async: true, + success: function (json) { + var item = json.updatepodresponse.pod; + args.response.success({ + actionFilter: podActionfilter, + data: item + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + 'remove': { + label: 'label.delete', + messages: { + confirm: function (args) { + return 'message.action.delete.pod'; + }, + notification: function (args) { + return 'label.action.delete.pod'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("deletePod&id=" + args.context.pods[0].id), + dataType: "json", + async: true, + success: function (json) { + args.response.success({ + data: { + } + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + } + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name', + isEditable: true, + validation: { + required: true + } + } + }, + { + id: { + label: 'label.id' + }, + netmask: { + label: 'label.netmask', + isEditable: true, + validation: { + required: true + } + }, + gateway: { + label: 'label.gateway', + isEditable: true, + validation: { + required: true + } + }, + allocationstate: { + converter: function (str) { + // For localization + return str; + }, + label: 'label.allocation.state' + } + }, { + isdedicated: { + label: 'label.dedicated' + }, + domainid: { + label: 'label.domain.id' + } + }], + + dataProvider: function (args) { + $.ajax({ + url: createURL("listPods&id=" + args.context.pods[0].id), + success: function (json) { + var item = json.listpodsresponse.pod[0]; + $.ajax({ + url: createURL("listDedicatedPods&podid=" + args.context.pods[0].id), + success: function (json) { + if (json.listdedicatedpodsresponse.dedicatedpod != undefined) { + var podItem = json.listdedicatedpodsresponse.dedicatedpod[0]; + if (podItem.domainid != null) { + $.extend(item, podItem, { + isdedicated: _l('label.yes') + }); + } + } else + $.extend(item, { + isdedicated: _l('label.no') + }); + + args.response.success({ + actionFilter: podActionfilter, + data: item + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + // args.response.success({ + // actionFilter: podActionfilter, + // data: item + // }); + } + }); + } + }, + + ipAllocations: { + title: 'label.ip.allocations', + multiple: true, + fields:[ { + id: { + label: 'label.id' + }, + gateway: { + label: 'label.gateway' + }, + netmask: { + label: 'label.netmask' + }, + startip: { + label: 'label.start.IP' + }, + endip: { + label: 'label.end.IP' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listVlanIpRanges&zoneid=" + args.context.zones[0].id + "&podid=" + args.context.pods[0].id), + dataType: "json", + success: function (json) { + var items = json.listvlaniprangesresponse.vlaniprange; + args.response.success({ + data: items + }); + } + }); + } + } + } + } + } + }, + clusters: { + title: 'label.clusters', + listView: { + id: 'clusters', + section: 'clusters', + multiSelect: true, + fields: { + name: { + label: 'label.name' + }, + hypervisortype: { + label: 'label.hypervisor' + }, + zonename: { + label: 'label.zone' + }, + podname: { + label: 'label.pod' + }, + managedstate: { + label: 'label.managed.state' + }, + allocationstate: { + converter: function (str) { + // For localization + return str; + }, + label: 'label.allocation.state', + indicator: { + 'Enabled': 'on', + 'Disabled': 'off' + } + } + }, + + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + array1.push("&zoneid=" + args.context.zones[0].id); + if ("pods" in args.context) + array1.push("&podid=" + args.context.pods[0].id); + $.ajax({ + url: createURL("listClusters" + array1.join("") + "&page=" + args.page + "&pagesize=" + pageSize), + dataType: "json", + async: true, + success: function (json) { + var items = json.listclustersresponse.cluster; + $(items).each(function () { + addExtraPropertiesToClusterObject(this); + }); + + args.response.success({ + actionFilter: clusterActionfilter, + data: items + }); + } + }); + }, + + actions: { + add: { + label: 'label.add.cluster', + messages: { + notification: function (args) { + return 'label.add.cluster'; + } + }, + createForm: { + title: 'label.add.cluster', + preFilter: function (args) { + var $form = args.$form; + $form.click(function () { + var $nexusDvsOptFields = $form.find('.form-item').filter(function () { + var nexusDvsOptFields =[ + 'vsmipaddress', + 'vsmusername', + 'vsmpassword']; + return $.inArray($(this).attr('rel'), nexusDvsOptFields) > -1; + }); + var $nexusDvsReqFields = $form.find('.form-item').filter(function () { + var nexusDvsReqFields =[ + 'vsmipaddress_req', + 'vsmusername_req', + 'vsmpassword_req']; + return $.inArray($(this).attr('rel'), nexusDvsReqFields) > -1; + }); + + if ($form.find('.form-item[rel=hypervisor] select').val() == 'VMware') { + $form.find('.form-item[rel=vCenterHost]').css('display', 'inline-block'); + $form.find('.form-item[rel=vCenterUsername]').css('display', 'inline-block'); + $form.find('.form-item[rel=vCenterPassword]').css('display', 'inline-block'); + $form.find('.form-item[rel=vCenterDatacenter]').css('display', 'inline-block'); + + var $overridePublicTraffic = $form.find('.form-item[rel=overridepublictraffic] input[type=checkbox]'); + var $vSwitchPublicType = $form.find('.form-item[rel=vSwitchPublicType] select'); + var $overrideGuestTraffic = $form.find('.form-item[rel=overrideguesttraffic] input[type=checkbox]'); + var $vSwitchGuestType = $form.find('.form-item[rel=vSwitchGuestType] select'); + + + var useDvs = false; + $.ajax({ + url: createURL('listConfigurations'), + data: { + name: 'vmware.use.dvswitch' + }, + async: false, + success: function (json) { + if (json.listconfigurationsresponse.configuration[0].value == 'true') { + useDvs = true; + } + } + }); + if (useDvs == true) { + //If using Distributed vswitch, there is OverrideTraffic option. + $form.find('.form-item[rel=overridepublictraffic]').css('display', 'inline-block'); + $form.find('.form-item[rel=overrideguesttraffic]').css('display', 'inline-block'); + + var useNexusDvs = false; + $.ajax({ + url: createURL('listConfigurations'), + data: { + name: 'vmware.use.nexus.vswitch' + }, + async: false, + success: function (json) { + if (json.listconfigurationsresponse.configuration[0].value == 'true') { + useNexusDvs = true; + } + } + }); + if (useNexusDvs == true) { + //If using Nexus Distributed vswitch, show Nexus Distributed vswitch fields (either required ones or optional ones). + if (($overridePublicTraffic.is(':checked') && $vSwitchPublicType.val() == 'nexusdvs') || + ($overrideGuestTraffic.is(':checked') && $vSwitchGuestType.val() == 'nexusdvs')) { + $nexusDvsReqFields.css('display', 'inline-block'); + $nexusDvsOptFields.hide(); + } else { + $nexusDvsOptFields.css('display', 'inline-block'); + $nexusDvsReqFields.hide(); + } + } else { + //If not using Nexus Distributed vswitch, hide Nexus Distributed vswitch fields. + $nexusDvsOptFields.hide(); + $nexusDvsReqFields.hide(); + } + } else { + //useDvs == false + $form.find('.form-item[rel=overridepublictraffic]').css('display', 'none'); + $form.find('.form-item[rel=vSwitchPublicType]').css('display', 'none'); + $form.find('.form-item[rel=vSwitchPublicName]').css('display', 'none'); + + $form.find('.form-item[rel=overrideguesttraffic]').css('display', 'none'); + $form.find('.form-item[rel=vSwitchGuestType]').css('display', 'none'); + $form.find('.form-item[rel=vSwitchGuestName]').css('display', 'none'); + + $nexusDvsOptFields.hide(); + $nexusDvsReqFields.hide(); + } + } else { + //XenServer, KVM, etc (non-VMware) + $form.find('.form-item[rel=vCenterHost]').css('display', 'none'); + $form.find('.form-item[rel=vCenterUsername]').css('display', 'none'); + $form.find('.form-item[rel=vCenterPassword]').css('display', 'none'); + $form.find('.form-item[rel=vCenterDatacenter]').css('display', 'none'); + $form.find('.form-item[rel=enableNexusVswitch]').css('display', 'none'); + + $form.find('.form-item[rel=overridepublictraffic]').css('display', 'none'); + $form.find('.form-item[rel=overrideguesttraffic]').css('display', 'none'); + $nexusDvsOptFields.hide(); + $nexusDvsReqFields.hide(); + } + + if ($form.find('.form-item[rel=overridepublictraffic]').css('display') != 'none' && $overridePublicTraffic.is(':checked')) { + $form.find('.form-item[rel=vSwitchPublicType]').css('display', 'inline-block'); + $form.find('.form-item[rel=vSwitchPublicName]').css('display', 'inline-block'); + } else { + $form.find('.form-item[rel=vSwitchPublicType]').css('display', 'none'); + $form.find('.form-item[rel=vSwitchPublicName]').css('display', 'none'); + } + + if ($form.find('.form-item[rel=overrideguesttraffic]').css('display') != 'none' && $overrideGuestTraffic.is(':checked')) { + $form.find('.form-item[rel=vSwitchGuestType]').css('display', 'inline-block'); + $form.find('.form-item[rel=vSwitchGuestName]').css('display', 'inline-block'); + } else { + $form.find('.form-item[rel=vSwitchGuestType]').css('display', 'none'); + $form.find('.form-item[rel=vSwitchGuestName]').css('display', 'none'); + } + }); + + $form.trigger('click'); + }, + fields: { + zoneid: { + label: 'label.zone.name', + docID: 'helpClusterZone', + validation: { + required: true + }, + select: function (args) { + var data = args.context.zones ? { + id: args.context.zones[0].id + }: {}; + + $.ajax({ + url: createURL('listZones'), + data: data, + success: function (json) { + var zones = json.listzonesresponse.zone ? json.listzonesresponse.zone:[]; + + args.response.success({ + data: $.map(zones, function (zone) { + return { + id: zone.id, + description: zone.name + }; + }) + }); + } + }); + } + }, + hypervisor: { + label: 'label.hypervisor', + docID: 'helpClusterHypervisor', + select: function (args) { + $.ajax({ + url: createURL("listHypervisors"), + dataType: "json", + async: false, + success: function (json) { + var hypervisors = json.listhypervisorsresponse.hypervisor; + var items =[]; + $(hypervisors).each(function () { + items.push({ + id: this.name, + description: this.name + }); + }); + args.response.success({ + data: items + }); + } + }); + } + }, + podId: { + label: 'label.pod.name', + docID: 'helpClusterPod', + dependsOn: 'zoneid', + select: function (args) { + $.ajax({ + url: createURL("listPods&zoneid=" + args.zoneid), + dataType: "json", + async: true, + success: function (json) { + var pods = json.listpodsresponse.pod; + var items =[]; + $(pods).each(function () { + if (("pods" in args.context) && (this.id == args.context.pods[0].id)) + items.unshift({ + id: this.id, + description: this.name + }); else + items.push({ + id: this.id, + description: this.name + }); + }); + args.response.success({ + data: items + }); + } + }); + } + }, + name: { + label: 'label.cluster.name', + docID: 'helpClusterName', + validation: { + required: true + } + }, + + isDedicated: { + label: 'label.dedicate', + isBoolean: true, + isChecked: false, + docID: 'helpDedicateResource' + }, + + domainId: { + label: 'label.domain', + isHidden: true, + validation: { + required: true + }, + dependsOn: 'isDedicated', + select: function (args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function (json) { + var domainObjs = json.listdomainsresponse.domain; + var items =[]; + + $(domainObjs).each(function () { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + + args.response.success({ + data: items + }); + } + }); + } + }, + + accountId: { + label: 'label.account', + isHidden: true, + dependsOn: 'isDedicated', + docID: 'helpAccountForDedication', + validation: { + required: false + } + }, + + //hypervisor==Ovm3 begins here + ovm3pool: { + label: 'label.ovm3.pool', + isHidden: true, + isBoolean: true, + isChecked: true, + docID: 'helpOvm3pool' + }, + ovm3cluster: { + label: 'label.ovm3.cluster', + isHidden: true, + isBoolean: true, + isChecked: false, + docID: 'helpOvm3cluster' + }, + ovm3vip: { + label: 'label.ovm3.vip', + isHidden: true, + docID: 'helpOvm3Vip', + validation: { + required: false + } + }, + + //hypervisor==VMWare begins here + vCenterHost: { + label: 'label.vcenter.host', + isHidden: true, + docID: 'helpClustervCenterHost', + validation: { + required: false + } + //legacy zone - validation not required for new VMware dc model + }, + vCenterUsername: { + label: 'label.vcenter.username', + isHidden: true, + docID: 'helpClustervCenterUsername' + }, + vCenterPassword: { + label: 'label.vcenter.password', + isHidden: true, + docID: 'helpClustervCenterPassword', + isPassword: true + }, + vCenterDatacenter: { + label: 'label.vcenter.datacenter', + isHidden: true, + docID: 'helpClustervCenterDatacenter', + validation: { + required: false + } + //legacy zone - validation not required for new VMware dc model + }, + + overridepublictraffic: { + label: 'label.override.public.traffic', + isBoolean: true, + isHidden: true, + isChecked: false, + docID: 'helpOverridePublicNetwork' + }, + + + vSwitchPublicType: { + label: 'label.public.traffic.vswitch.type', + select: function (args) { + var useNexusDvs = false; + var items =[] + $.ajax({ + url: createURL('listConfigurations'), + data: { + name: 'vmware.use.nexus.vswitch' + }, + async: false, + success: function (json) { + if (json.listconfigurationsresponse.configuration[0].value == 'true') { + useNexusDvs = true; + } + } + }); + + if (useNexusDvs) { + items.push({ + id: "nexusdvs", + description: "Cisco Nexus 1000v Distributed Virtual Switch" + }); + items.push({ + id: "vmwaresvs", + description: "VMware vNetwork Standard Virtual Switch" + }); + items.push({ + id: "vmwaredvs", + description: "VMware vNetwork Distributed Virtual Switch" + }); + } else { + items.push({ + id: "vmwaredvs", + description: "VMware vNetwork Distributed Virtual Switch" + }); + items.push({ + id: "vmwaresvs", + description: "VMware vNetwork Standard Virtual Switch" + }); + items.push({ + id: "nexusdvs", + description: "Cisco Nexus 1000v Distributed Virtual Switch" + }); + } + + args.response.success({ + data: items + }); + }, + isHidden: true + }, + + vSwitchPublicName: { + label: 'label.public.traffic.vswitch.name', + isHidden: true + }, + + overrideguesttraffic: { + label: 'label.override.guest.traffic', + isBoolean: true, + isHidden: true, + isChecked: false, + docID: 'helpOverrideGuestNetwork' + }, + + vSwitchGuestType: { + label: 'label.guest.traffic.vswitch.type', + select: function (args) { + var items =[] + + var useNexusDvs = false; + $.ajax({ + url: createURL('listConfigurations'), + data: { + name: 'vmware.use.nexus.vswitch' + }, + async: false, + success: function (json) { + if (json.listconfigurationsresponse.configuration[0].value == 'true') { + useNexusDvs = true; + } + } + }); + + + if (useNexusDvs) { + items.push({ + id: "nexusdvs", + description: "Cisco Nexus 1000v Distributed Virtual Switch" + }); + items.push({ + id: "vmwaresvs", + description: "VMware vNetwork Standard Virtual Switch" + }); + items.push({ + id: "vmwaredvs", + description: "VMware vNetwork Distributed Virtual Switch" + }); + } else { + items.push({ + id: "vmwaredvs", + description: "VMware vNetwork Distributed Virtual Switch" + }); + items.push({ + id: "vmwaresvs", + description: "VMware vNetwork Standard Virtual Switch" + }); + items.push({ + id: "nexusdvs", + description: "Cisco Nexus 1000v Distributed Virtual Switch" + }); + } + + args.response.success({ + data: items + }); + }, + isHidden: true + }, + + vSwitchGuestName: { + label: 'label.guest.traffic.vswitch.name', + isHidden: true + }, + + + vsmipaddress: { + label: 'label.cisco.nexus1000v.ip.address', + validation: { + required: false + }, + isHidden: true + }, + vsmipaddress_req: { + label: 'label.cisco.nexus1000v.ip.address', + validation: { + required: true + }, + isHidden: true + }, + vsmusername: { + label: 'label.cisco.nexus1000v.username', + validation: { + required: false + }, + isHidden: true + }, + vsmusername_req: { + label: 'label.cisco.nexus1000v.username', + validation: { + required: true + }, + isHidden: true + }, + vsmpassword: { + label: 'label.cisco.nexus1000v.password', + validation: { + required: false + }, + isPassword: true, + isHidden: true + }, + vsmpassword_req: { + label: 'label.cisco.nexus1000v.password', + validation: { + required: true + }, + isPassword: true, + isHidden: true + } + //hypervisor==VMWare ends here + } + }, + + action: function (args) { + var array1 =[]; + array1.push("&zoneId=" + args.data.zoneid); + array1.push("&hypervisor=" + args.data.hypervisor); + + var clusterType; + if (args.data.hypervisor == "VMware") + clusterType = "ExternalManaged"; else + clusterType = "CloudManaged"; + array1.push("&clustertype=" + clusterType); + + array1.push("&podId=" + args.data.podId); + + var clusterName = args.data.name; + if (args.data.hypervisor == "Ovm3") { + array1.push("&ovm3pool=" + encodeURIComponent(args.data.ovm3pool)); + array1.push("&ovm3cluster=" + encodeURIComponent(args.data.ovm3cluster)); + array1.push("&ovm3vip=" + encodeURIComponent(args.data.ovm3vip)); + } + if (args.data.hypervisor == "VMware") { + cloudStack.addUsernameAndPasswordToCommandUrlParameterArrayIfItIsNotNullAndNotEmpty(array1, args.data.vCenterUsername, args.data.vCenterPassword); + + //vSwitch Public Type + if (args.$form.find('.form-item[rel=vSwitchPublicType]').css('display') != 'none' && args.data.vSwitchPublicType != "") { + array1.push("&publicvswitchtype=" + args.data.vSwitchPublicType); + } + if (args.$form.find('.form-item[rel=vSwitchPublicName]').css('display') != 'none' && args.data.vSwitchPublicName != "") { + array1.push("&publicvswitchname=" + args.data.vSwitchPublicName); + } + + //vSwitch Guest Type + if (args.$form.find('.form-item[rel=vSwitchGuestType]').css('display') != 'none' && args.data.vSwitchGuestType != "") { + array1.push("&guestvswitchtype=" + args.data.vSwitchGuestType); + } + if (args.$form.find('.form-item[rel=vSwitchGuestName]').css('display') != 'none' && args.data.vSwitchGuestName != "") { + array1.push("&guestvswitchname=" + args.data.vSwitchGuestName); + } + + //Nexus VSM fields + if (args.$form.find('.form-item[rel=vsmipaddress]').css('display') != 'none' && args.data.vsmipaddress != null && args.data.vsmipaddress.length > 0) { + array1.push('&vsmipaddress=' + args.data.vsmipaddress); + } + if (args.$form.find('.form-item[rel=vsmipaddress_req]').css('display') != 'none' && args.data.vsmipaddress_req != null && args.data.vsmipaddress_req.length > 0) { + array1.push('&vsmipaddress=' + args.data.vsmipaddress_req); + } + + if (args.$form.find('.form-item[rel=vsmusername]').css('display') != 'none' && args.data.vsmusername != null && args.data.vsmusername.length > 0) { + array1.push('&vsmusername=' + args.data.vsmusername); + } + if (args.$form.find('.form-item[rel=vsmusername_req]').css('display') != 'none' && args.data.vsmusername_req != null && args.data.vsmusername_req.length > 0) { + array1.push('&vsmusername=' + args.data.vsmusername_req); + } + + if (args.$form.find('.form-item[rel=vsmpassword]').css('display') != 'none' && args.data.vsmpassword != null && args.data.vsmpassword.length > 0) { + array1.push('&vsmpassword=' + args.data.vsmpassword); + } + if (args.$form.find('.form-item[rel=vsmpassword_req]').css('display') != 'none' && args.data.vsmpassword_req != null && args.data.vsmpassword_req.length > 0) { + array1.push('&vsmpassword=' + args.data.vsmpassword_req); + } + + + var hostname = args.data.vCenterHost; + var dcName = args.data.vCenterDatacenter; + + if (hostname.length == 0 && dcName.length == 0) { + $.ajax({ + url: createURL('listVmwareDcs'), + data: { + zoneid: args.data.zoneid + }, + async: false, + success: function (json) { + //e.g. json == { "listvmwaredcsresponse" { "count":1 ,"VMwareDC" [ {"id":"c3c2562d-65e9-4fc7-92e2-773c2efe8f37","zoneid":1,"name":"datacenter","vcenter":"10.10.20.20"} ] } } + var vmwaredcs = json.listvmwaredcsresponse.VMwareDC; + if (vmwaredcs != null) { + hostname = vmwaredcs[0].vcenter; + dcName = vmwaredcs[0].name; + } + } + }); + } + + var url; + if (hostname.indexOf("http://") == -1) + url = "http://" + hostname; else + url = hostname; + url += "/" + dcName + "/" + clusterName; + array1.push("&url=" + encodeURIComponent(url)); + + clusterName = hostname + "/" + dcName + "/" + clusterName; //override clusterName + } + array1.push("&clustername=" + encodeURIComponent(clusterName)); + var clusterId = null; + $.ajax({ + url: createURL("addCluster" + array1.join("")), + dataType: "json", + type: "POST", + success: function (json) { + var item = json.addclusterresponse.cluster[0]; + clusterId = json.addclusterresponse.cluster[0].id; + + //EXPLICIT DEDICATION + var array2 =[]; + if (args.$form.find('.form-item[rel=isDedicated]').find('input[type=checkbox]').is(':Checked') == true) { + if (args.data.accountId != "") + array2.push("&account=" + encodeURIComponent(args.data.accountId)); + + if (clusterId != null) { + $.ajax({ + url: createURL("dedicateCluster&clusterId=" + clusterId + "&domainId=" + args.data.domainId + array2.join("")), + dataType: "json", + success: function (json) { + var jid = json.dedicateclusterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + }, + notification: { + poll: pollAsyncJobResult, + interval: 4500, + desc: "Dedicate Cluster" + }, + + data: $.extend(item, { + state: 'Enabled' + }) + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + } + } + args.response.success({ + data: item, + actionFilter: clusterActionfilter + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + } + }, + viewMetrics: { + label: 'label.metrics', + isHeader: true, + addRow: false, + action: { + custom: cloudStack.uiCustom.metricsView({resource: 'clusters'}) + }, + messages: { + notification: function (args) { + return 'label.metrics'; + } + } + }, + startRollingMaintenance: rollingMaintenanceAction({ listView: true, entity: 'clusters' }) + }, + + detailView: { + viewAll: { + path: '_zone.hosts', + label: 'label.hosts' + }, + isMaximized: true, + tabFilter: function (args) { + var vSwichConfigEnabled, vSwitchPresentOnCluster; + $.ajax({ + url: createURL('listConfigurations'), + data: { + name: 'vmware.use.nexus.vswitch' + }, + async: false, + success: function (json) { + vSwichConfigEnabled = json.listconfigurationsresponse.configuration[0].value; + } + }); + + var hypervisorType = args.context.clusters[0].hypervisortype; + if (vSwichConfigEnabled != "true" || hypervisorType != 'VMware') { + return[ 'nexusVswitch']; + } + return[]; + }, + + actions: { + + startRollingMaintenance: { + label: 'label.start.rolling.maintenance', + textLabel: 'label.start.rolling.maintenance', + messages: { + notification: function (args) { + return 'label.start.rolling.maintenance'; + } + }, + createForm: { + title: 'label.start.rolling.maintenance', + fields: { + timeout: { + label: 'label.timeout', + }, + force: { + isBoolean: true, + label: 'label.start.rolling.maintenance.force' + }, + payload: { + label: 'label.start.rolling.maintenance.payload' + } + } + }, + action: function (args) { + var data = { + clusterids: args.context.clusters[0].id, + force: args.data.force, + timeout: args.data.timeout, + payload: args.data.payload + }; + $.ajax({ + url: createURL("startRollingMaintenance"), + dataType: "json", + data: data, + async: true, + success: function (json) { + var item = json.rollingmaintenance; + args.response.success({ + actionFilter: zoneActionfilter, + data: item + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + edit: { + label: 'label.edit', + action: function (args) { + var array1 =[]; + + $.ajax({ + url: createURL("updateCluster&id=" + args.context.clusters[0].id + array1.join("")), + dataType: "json", + async: true, + success: function (json) { + var item = json.updateclusterresponse.cluster; + addExtraPropertiesToClusterObject(item); + args.response.success({ + actionFilter: clusterActionfilter, + data: item + }); + } + }); + } + }, + + enable: { + label: 'label.action.enable.cluster', + messages: { + confirm: function (args) { + return 'message.action.enable.cluster'; + }, + notification: function (args) { + return 'label.action.enable.cluster'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("updateCluster&id=" + args.context.clusters[0].id + "&allocationstate=Enabled"), + dataType: "json", + async: true, + success: function (json) { + var item = json.updateclusterresponse.cluster; + args.context.clusters[0].state = item.allocationstate; + addExtraPropertiesToClusterObject(item); + args.response.success({ + actionFilter: clusterActionfilter, + data: item + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + disable: { + label: 'label.action.disable.cluster', + messages: { + confirm: function (args) { + return 'message.action.disable.cluster'; + }, + notification: function (args) { + return 'label.action.disable.cluster'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("updateCluster&id=" + args.context.clusters[0].id + "&allocationstate=Disabled"), + dataType: "json", + async: true, + success: function (json) { + var item = json.updateclusterresponse.cluster; + args.context.clusters[0].state = item.allocationstate; + addExtraPropertiesToClusterObject(item); + args.response.success({ + actionFilter: clusterActionfilter, + data: item + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + dedicate: { + label: 'label.dedicate.cluster', + messages: { + confirm: function (args) { + return 'message.confirm.dedicate.cluster.domain.account'; + }, + notification: function (args) { + return 'message.cluster.dedicated'; + } + }, + createForm: { + title: 'label.dedicate.cluster', + fields: { + domainId: { + label: 'label.domain', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function (json) { + var domainObjs = json.listdomainsresponse.domain; + var items =[]; + + $(domainObjs).each(function () { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + + args.response.success({ + data: items + }); + } + }); + } + }, + accountId: { + label: 'label.account', + docID: 'helpAccountForDedication', + validation: { + required: false + } + } + } + }, + action: function (args) { + //EXPLICIT DEDICATION + var array2 =[]; + if (args.data.accountId != "") + array2.push("&account=" + encodeURIComponent(args.data.accountId)); + $.ajax({ + url: createURL("dedicateCluster&clusterId=" + + args.context.clusters[0].id + + "&domainId=" + args.data.domainId + array2.join("")), + dataType: "json", + success: function (json) { + var jid = json.dedicateclusterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return clusterActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + release: { + label: 'label.release.dedicated.cluster', + messages: { + confirm: function (args) { + return 'message.confirm.release.dedicated.cluster'; + }, + notification: function (args) { + return 'message.cluster.dedication.released'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("releaseDedicatedCluster&clusterid=" + args.context.clusters[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.releasededicatedclusterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return clusterActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + + manage: { + label: 'label.action.manage.cluster', + messages: { + confirm: function (args) { + return 'message.action.manage.cluster'; + }, + notification: function (args) { + return 'label.action.manage.cluster'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("updateCluster&id=" + args.context.clusters[0].id + "&managedstate=Managed"), + dataType: "json", + async: true, + success: function (json) { + var item = json.updateclusterresponse.cluster; + addExtraPropertiesToClusterObject(item); + args.response.success({ + actionFilter: clusterActionfilter, + data: item + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + unmanage: { + label: 'label.action.unmanage.cluster', + messages: { + confirm: function (args) { + return 'message.action.unmanage.cluster'; + }, + notification: function (args) { + return 'label.action.unmanage.cluster'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("updateCluster&id=" + args.context.clusters[0].id + "&managedstate=Unmanaged"), + dataType: "json", + async: true, + success: function (json) { + var item = json.updateclusterresponse.cluster; + addExtraPropertiesToClusterObject(item); + args.response.success({ + actionFilter: clusterActionfilter, + data: item + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + 'remove': { + label: 'label.action.delete.cluster', + messages: { + confirm: function (args) { + return 'message.action.delete.cluster'; + }, + notification: function (args) { + return 'label.action.delete.cluster'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("deleteCluster&id=" + args.context.clusters[0].id), + dataType: "json", + async: true, + success: function (json) { + args.response.success({ + data: { + } + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + enableOutOfBandManagement: { + label: 'label.outofbandmanagement.enable', + action: function (args) { + var data = { + clusterid: args.context.clusters[0].id, + }; + $.ajax({ + url: createURL("enableOutOfBandManagementForCluster"), + data: data, + success: function (json) { + var jid = json.enableoutofbandmanagementforclusterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return clusterActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.enable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.enable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + disableOutOfBandManagement: { + label: 'label.outofbandmanagement.disable', + action: function (args) { + var data = { + clusterid: args.context.clusters[0].id, + }; + $.ajax({ + url: createURL("disableOutOfBandManagementForCluster"), + data: data, + success: function (json) { + var jid = json.disableoutofbandmanagementforclusterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return clusterActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.disable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.disable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + enableHA: { + label: 'label.ha.enable', + action: function (args) { + var data = { + clusterid: args.context.clusters[0].id + }; + $.ajax({ + url: createURL("enableHAForCluster"), + data: data, + success: function (json) { + var jid = json.enablehaforclusterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return clusterActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + messages: { + confirm: function (args) { + return 'label.ha.enable'; + }, + notification: function (args) { + return 'label.ha.enable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disableHA: { + label: 'label.ha.disable', + action: function (args) { + var data = { + clusterid: args.context.clusters[0].id + }; + $.ajax({ + url: createURL("disableHAForCluster"), + data: data, + success: function (json) { + var jid = json.disablehaforclusterresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return clusterActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + messages: { + confirm: function (args) { + return 'label.ha.disable'; + }, + notification: function (args) { + return 'label.ha.disable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + } + }, + + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + id: { + label: 'label.id' + }, + zonename: { + label: 'label.zone' + }, + podname: { + label: 'label.pod' + }, + hypervisortype: { + label: 'label.hypervisor' + }, + clustertype: { + label: 'label.cluster.type' + }, + //allocationstate: { label: 'label.allocation.state' }, + //managedstate: { label: 'Managed State' }, + state: { + label: 'label.state' + } + }, { + isdedicated: { + label: 'label.dedicated' + }, + domainid: { + label: 'label.domain.id' + } + }], + dataProvider: function (args) { + $.ajax({ + url: createURL("listClusters&id=" + args.context.clusters[0].id), + dataType: "json", + success: function (json) { + var item = json.listclustersresponse.cluster[0]; + addExtraPropertiesToClusterObject(item); + $.ajax({ + url: createURL("listDedicatedClusters&clusterid=" + args.context.clusters[0].id), + dataType: "json", + async: false, + success: function (json) { + if (json.listdedicatedclustersresponse.dedicatedcluster != undefined) { + var clusterItem = json.listdedicatedclustersresponse.dedicatedcluster[0]; + if (clusterItem.domainid != null) { + $.extend(item, clusterItem, { + isdedicated: _l('label.yes') + }); + } + } else + $.extend(item, { + isdedicated: _l('label.no') + }) + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + args.response.success({ + actionFilter: clusterActionfilter, + data: item + }); + }, + + error: function (json) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + } + }, + nexusVswitch: { + title: 'label.nexusVswitch', + listView: { + id: 'vSwitches', + fields: { + vsmdeviceid: { + label: 'label.name' + }, + vsmdevicestate: { + label: 'label.state', + indicator: { + 'Enabled': 'on' + } + } + }, + detailView: { + actions: { + enable: { + label: 'label.action.enable.nexusVswitch', + messages: { + confirm: function (args) { + return 'message.action.enable.nexusVswitch'; + }, + notification: function (args) { + return 'label.action.enable.nexusVswitch'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("enableCiscoNexusVSM&id=" + args.context.vSwitches[0].vsmdeviceid), + dataType: "json", + async: true, + success: function (json) { + var jid = json.enablecisconexusvsmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + //args.context.vSwitches[0].vsmdevicestate = item.allocationstate; + //addExtraPropertiesToClusterObject(item); + args.response.success({ + actionFilter: nexusActionfilter, + data: item + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + disable: { + label: 'label.action.disable.nexusVswitch', + messages: { + confirm: function (args) { + return 'message.action.disable.nexusVswitch'; + }, + notification: function (args) { + return 'label.action.disable.nexusVswitch'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("disableCiscoNexusVSM&id=" + args.context.vSwitches[0].vsmdeviceid), + dataType: "json", + async: true, + success: function (json) { + var jid = json.disablecisconexusvsmresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + //args.context.vSwitches[0].vsmdevicestate = item.allocationstate; + //addExtraPropertiesToClusterObject(item); + args.response.success({ + actionFilter: nexusActionfilter, + data: item + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + } + + /* 'remove': { + label: 'label.action.delete.nexusVswitch' , + messages: { + confirm: function(args) { + return 'message.action.delete.nexusVswitch'; + }, + notification: function(args) { + return 'label.action.delete.nexusVswitch'; + } + }, + action: function(args) { + $.ajax({ + url: createURL("deleteCiscoNexusVSM&id=" + args.context.vSwitches[0].vsmdeviceid), + dataType: "json", + async: true, + success: function(json) { + args.response.success({data:{}}); + } + }); + }, + notification: { + poll: function(args) { args.complete(); } + } + }*/ + }, + + tabs: { + details: { + title: 'label.details', + fields: { + vsmdeviceid: { + label: 'label.name' + }, + ipaddress: { + label: 'label.ipaddress' + }, + vsmctrlvlanid: { + label: 'label.vsmctrlvlanid' + }, + vsmpktvlanid: { + label: 'label.vsmpktvlanid' + }, + vsmstoragevlanid: { + label: 'label.vsmstoragevlanid' + }, + vsmdevicestate: { + label: 'label.state', + indicator: { + 'Enabled': 'on' + } + } + }, + + dataProvider: function (args) { + $.ajax({ + url: createURL("listCiscoNexusVSMs&clusterid=" + args.context.clusters[0].id), + dataType: "json", + success: function (json) { + var item = json.listcisconexusvsmscmdresponse.cisconexusvsm[0]; + addExtraPropertiesToClusterObject(item); + args.response.success({ + actionFilter: nexusActionfilter, + data: item + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + } + }, + + dataProvider: function (args) { + $.ajax({ + url: createURL("listCiscoNexusVSMs&clusterid=" + args.context.clusters[0].id), + dataType: "json", + success: function (json) { + var item = json.listcisconexusvsmscmdresponse.cisconexusvsm; + args.response.success({ + actionFilter: nexusActionfilter, + data: item + }); + }, + error: function (json) { + // Not generally a real error; means vSwitch still needs setup + args.response.success({ + data:[] + }); + } + }); + } + } + }, + + // Granular settings for cluster + settings: { + title: 'label.settings', + custom: cloudStack.uiCustom.granularSettings({ + dataProvider: function (args) { + $.ajax({ + url: createURL('listConfigurations&clusterid=' + args.context.clusters[0].id), + data: listViewDataProvider(args, { + }, + { + searchBy: 'name' + }), + success: function (json) { + args.response.success({ + data: json.listconfigurationsresponse.configuration + }); + }, + + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + actions: { + edit: function (args) { + // call updateClusterLevelParameters + + var data = { + name: args.data.jsonObj.name, + value: args.data.value + }; + + $.ajax({ + url: createURL('updateConfiguration&clusterid=' + args.context.clusters[0].id), + data: data, + success: function (json) { + var item = json.updateconfigurationresponse.configuration; + + if (args.data.jsonObj.name == 'cpu.overprovisioning.factor' || args.data.jsonObj.name == 'mem.overprovisioning.factor') { + cloudStack.dialog.notice({ + message: 'Please note - if you are changing the over provisioning factor for a cluster with vms running, please refer to the admin guide to understand the capacity calculation.' + }); + } + + args.response.success({ + data: item + }); + }, + + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + }) + } + } + } + } + }, + hosts: { + title: 'label.hosts', + id: 'hosts', + listView: { + section: 'hosts', + id: 'hosts', + multiSelect: true, + fields: { + name: { + label: 'label.name' + }, + ipaddress: { + label: 'label.ip.address' + }, + hypervisor: { + label: 'label.hypervisor' + }, + zonename: { + label: 'label.zone' + }, + clustername: { + label: 'label.cluster' + }, + resourcestate: { + label: 'label.resource.state', + indicator: { + 'Enabled': 'on', + 'Disabled': 'off', + 'Maintenance': 'warning' + } + }, + state: { + label: 'label.state', + indicator: { + 'Up': 'on', + 'Down': 'off', + 'Disconnected': 'off', + 'Alert': 'off', + 'Error': 'off', + 'Unsecure': 'warning' + } + }, + powerstate: { + label: 'label.powerstate', + indicator: { + 'On': 'on', + 'Off': 'off', + 'Unknown': 'warning' + }, + }, + }, + + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + + if (! args.context.instances) { + if ("zones" in args.context) + array1.push("&zoneid=" + args.context.zones[0].id); + if ("pods" in args.context) + array1.push("&podid=" + args.context.pods[0].id); + if ("clusters" in args.context) + array1.push("&clusterid=" + args.context.clusters[0].id); + } else { + //Instances menu > Instance detailView > View Hosts + array1.push("&id=" + args.context.instances[0].hostid); + } + $.ajax({ + url: createURL("listHosts&type=Routing" + array1.join("") + "&page=" + args.page + "&pagesize=" + pageSize), + dataType: "json", + async: true, + success: function (json) { + var items = json.listhostsresponse.host; + if (items) { + $.each(items, function(idx, host) { + if (host && host.outofbandmanagement) { + items[idx].powerstate = host.outofbandmanagement.powerstate; + } + + if (host && host.hypervisor == "KVM" && host.state == 'Up' && host.details && host.details["secured"] != 'true') { + items[idx].state = 'Unsecure'; + } + }); + } + + args.response.success({ + actionFilter: hostActionfilter, + data: items + }); + } + }); + }, + + actions: { + add: { + label: 'label.add.host', + + createForm: { + title: 'label.add.host', + fields: { + zoneid: { + docID: 'helpHostZone', + label: 'label.zone', + validation: { + required: true + }, + select: function (args) { + var data = args.context.zones ? { + id: args.context.zones[0].id + }: {}; + + $.ajax({ + url: createURL('listZones'), + data: data, + success: function (json) { + var zones = json.listzonesresponse.zone ? json.listzonesresponse.zone:[]; + + args.response.success({ + data: $.map(zones, function (zone) { + return { + id: zone.id, + description: zone.name + }; + }) + }); + } + }); + } + }, + + //always appear (begin) + podId: { + label: 'label.pod', + docID: 'helpHostPod', + validation: { + required: true + }, + dependsOn: 'zoneid', + select: function (args) { + $.ajax({ + url: createURL("listPods&zoneid=" + args.zoneid), + dataType: "json", + async: true, + success: function (json) { + var pods = json.listpodsresponse.pod; + var items =[]; + $(pods).each(function () { + if (("pods" in args.context) && (this.id == args.context.pods[0].id)) + items.unshift({ + id: this.id, + description: this.name + }); else + items.push({ + id: this.id, + description: this.name + }); + }); + args.response.success({ + data: items + }); + } + }); + } + }, + + clusterId: { + label: 'label.cluster', + docID: 'helpHostCluster', + validation: { + required: true + }, + dependsOn: 'podId', + select: function (args) { + $.ajax({ + url: createURL("listClusters&podid=" + args.podId), + dataType: "json", + async: false, + success: function (json) { + clusterObjs = json.listclustersresponse.cluster; + var items =[]; + $(clusterObjs).each(function () { + if (("clusters" in args.context) && (this.id == args.context.clusters[0].id)) + items.unshift({ + id: this.id, + description: this.name + }); else + items.push({ + id: this.id, + description: this.name + }); + }); + args.response.success({ + data: items + }); + } + }); + + args.$select.change(function () { + var $form = $(this).closest('form'); + + var clusterId = $(this).val(); + if (clusterId == null) + return; + + var items =[]; + $(clusterObjs).each(function () { + if (this.id == clusterId) { + selectedClusterObj = this; + return false; //break the $.each() loop + } + }); + if (selectedClusterObj == null) + return; + + if (selectedClusterObj.hypervisortype == "VMware") { + //$('li[input_group="general"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=hostname]').hide(); + $form.find('.form-item[rel=username]').hide(); + $form.find('.form-item[rel=password]').hide(); + + //$('li[input_group="vmware"]', $dialogAddHost).show(); + $form.find('.form-item[rel=vcenterHost]').css('display', 'inline-block'); + + //$('li[input_group="baremetal"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=baremetalCpuCores]').hide(); + $form.find('.form-item[rel=baremetalCpu]').hide(); + $form.find('.form-item[rel=baremetalMemory]').hide(); + $form.find('.form-item[rel=baremetalMAC]').hide(); + + //$('li[input_group="Ovm"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=agentUsername]').hide(); + $form.find('.form-item[rel=agentPassword]').hide(); + + //$('li[input_group="Ovm3"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=agentUsername]').hide(); + $form.find('.form-item[rel=agentPassword]').hide(); + $form.find('.form-item[rel=agentPort]').hide(); + $form.find('.form-item[rel=ovm3vip]').hide(); + $form.find('.form-item[rel=ovm3pool]').hide(); + $form.find('.form-item[rel=ovm3cluster]').hide(); + } else if (selectedClusterObj.hypervisortype == "BareMetal") { + //$('li[input_group="general"]', $dialogAddHost).show(); + $form.find('.form-item[rel=hostname]').css('display', 'inline-block'); + $form.find('.form-item[rel=username]').css('display', 'inline-block'); + $form.find('.form-item[rel=password]').css('display', 'inline-block'); + + //$('li[input_group="baremetal"]', $dialogAddHost).show(); + $form.find('.form-item[rel=baremetalCpuCores]').css('display', 'inline-block'); + $form.find('.form-item[rel=baremetalCpu]').css('display', 'inline-block'); + $form.find('.form-item[rel=baremetalMemory]').css('display', 'inline-block'); + $form.find('.form-item[rel=baremetalMAC]').css('display', 'inline-block'); + + //$('li[input_group="vmware"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=vcenterHost]').hide(); + + //$('li[input_group="Ovm"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=agentUsername]').hide(); + $form.find('.form-item[rel=agentPassword]').hide(); + + //$('li[input_group="Ovm3"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=agentUsername]').hide(); + $form.find('.form-item[rel=agentPassword]').hide(); + $form.find('.form-item[rel=agentPort]').hide(); + $form.find('.form-item[rel=ovm3vip]').hide(); + $form.find('.form-item[rel=ovm3pool]').hide(); + $form.find('.form-item[rel=ovm3cluster]').hide(); + } else if (selectedClusterObj.hypervisortype == "Ovm") { + //$('li[input_group="general"]', $dialogAddHost).show(); + $form.find('.form-item[rel=hostname]').css('display', 'inline-block'); + $form.find('.form-item[rel=username]').css('display', 'inline-block'); + $form.find('.form-item[rel=password]').css('display', 'inline-block'); + + //$('li[input_group="vmware"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=vcenterHost]').hide(); + + //$('li[input_group="baremetal"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=baremetalCpuCores]').hide(); + $form.find('.form-item[rel=baremetalCpu]').hide(); + $form.find('.form-item[rel=baremetalMemory]').hide(); + $form.find('.form-item[rel=baremetalMAC]').hide(); + + //$('li[input_group="Ovm"]', $dialogAddHost).show(); + $form.find('.form-item[rel=agentUsername]').css('display', 'inline-block'); + $form.find('.form-item[rel=agentUsername]').find('input').val("oracle"); + $form.find('.form-item[rel=agentPassword]').css('display', 'inline-block'); + + //$('li[input_group="Ovm3"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=agentUsername]').hide(); + $form.find('.form-item[rel=agentPassword]').hide(); + $form.find('.form-item[rel=agentPort]').hide(); + $form.find('.form-item[rel=ovm3vip]').hide(); + $form.find('.form-item[rel=ovm3pool]').hide(); + $form.find('.form-item[rel=ovm3cluster]').hide(); + } else if (selectedClusterObj.hypervisortype == "Ovm3") { + //$('li[input_group="general"]', $dialogAddHost).show(); + $form.find('.form-item[rel=hostname]').css('display', 'inline-block'); + $form.find('.form-item[rel=username]').css('display', 'inline-block'); + $form.find('.form-item[rel=password]').css('display', 'inline-block'); + + //$('li[input_group="vmware"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=vcenterHost]').hide(); + + //$('li[input_group="baremetal"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=baremetalCpuCores]').hide(); + $form.find('.form-item[rel=baremetalCpu]').hide(); + $form.find('.form-item[rel=baremetalMemory]').hide(); + $form.find('.form-item[rel=baremetalMAC]').hide(); + + //$('li[input_group="Ovm3"]', $dialogAddHost).show(); + $form.find('.form-item[rel=agentUsername]').css('display', 'inline-block'); + $form.find('.form-item[rel=agentUsername]').find('input').val("oracle"); + $form.find('.form-item[rel=agentPassword]').css('display', 'inline-block'); + $form.find('.form-item[rel=agentPort]').css('display', 'inline-block'); + $form.find('.form-item[rel=agentPort]').find('input').val("8899"); + $form.find('.form-item[rel=ovm3vip]').css('display', 'inline-block'); + $form.find('.form-item[rel=ovm3pool]').css('display', 'inline-block'); + $form.find('.form-item[rel=ovm3cluster]').css('display', 'inline-block'); + } else { + //$('li[input_group="general"]', $dialogAddHost).show(); + $form.find('.form-item[rel=hostname]').css('display', 'inline-block'); + $form.find('.form-item[rel=username]').css('display', 'inline-block'); + $form.find('.form-item[rel=password]').css('display', 'inline-block'); + + //$('li[input_group="vmware"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=vcenterHost]').hide(); + + //$('li[input_group="baremetal"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=baremetalCpuCores]').hide(); + $form.find('.form-item[rel=baremetalCpu]').hide(); + $form.find('.form-item[rel=baremetalMemory]').hide(); + $form.find('.form-item[rel=baremetalMAC]').hide(); + + //$('li[input_group="Ovm"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=agentUsername]').hide(); + $form.find('.form-item[rel=agentPassword]').hide(); + + //$('li[input_group="Ovm3"]', $dialogAddHost).hide(); + $form.find('.form-item[rel=agentUsername]').hide(); + $form.find('.form-item[rel=agentPassword]').hide(); + $form.find('.form-item[rel=agentPort]').hide(); + $form.find('.form-item[rel=ovm3vip]').hide(); + $form.find('.form-item[rel=ovm3pool]').hide(); + $form.find('.form-item[rel=ovm3cluster]').hide(); + } + }); + + args.$select.trigger("change"); + } + }, + //always appear (end) + + //input_group="general" starts here + hostname: { + label: 'label.host.name', + docID: 'helpHostName', + validation: { + required: true + }, + isHidden: true + }, + + username: { + label: 'label.username', + docID: 'helpHostUsername', + validation: { + required: true + }, + isHidden: true + }, + + password: { + label: 'label.password', + docID: 'helpHostPassword', + validation: { + required: true + }, + isHidden: true, + isPassword: true + }, + + isDedicated: { + label: 'label.dedicate', + isBoolean: true, + isChecked: false, + docID: 'helpDedicateResource' + }, + + domainId: { + label: 'label.domain', + isHidden: true, + validation: { + required: true + }, + dependsOn: 'isDedicated', + select: function (args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + success: function (json) { + var domainObjs = json.listdomainsresponse.domain; + var items =[]; + + $(domainObjs).each(function () { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + + args.response.success({ + data: items + }); + } + }); + } + }, + + accountId: { + label: 'label.account', + isHidden: true, + dependsOn: 'isDedicated', + docID: 'helpAccountForDedication', + validation: { + required: false + } + }, + + //input_group="general" ends here + + //input_group="VMWare" starts here + vcenterHost: { + label: 'label.esx.host', + validation: { + required: true + }, + isHidden: true + }, + //input_group="VMWare" ends here + + //input_group="BareMetal" starts here + baremetalCpuCores: { + label: 'label.num.cpu.cores', + validation: { + required: true + }, + isHidden: true + }, + baremetalCpu: { + label: 'label.cpu.mhz', + validation: { + required: true + }, + isHidden: true + }, + baremetalMemory: { + label: 'label.memory.mb', + validation: { + required: true + }, + isHidden: true + }, + baremetalMAC: { + label: 'label.host.MAC', + validation: { + required: true + }, + isHidden: true + }, + //input_group="BareMetal" ends here + + //input_group="OVM" starts here + agentUsername: { + label: 'label.agent.username', + validation: { + required: false + }, + isHidden: true + }, + agentPassword: { + label: 'label.agent.password', + validation: { + required: true + }, + isHidden: true, + isPassword: true + }, + //input_group="OVM" ends here + + //input_group="OVM3" starts here + agentPort: { + label: 'label.agent.port', + validation: { + required: false + }, + isHidden: true + }, + //input_group="OVM3" ends here + + //always appear (begin) + hosttags: { + label: 'label.host.tags', + isTokenInput: true, + docID: 'helpHostTags', + validation: { + required: false + }, + dataProvider: function(args) { + $.ajax({ + url: createURL("listHostTags"), + dataType: "json", + success: function(json) { + var item = json.listhosttagsresponse.hosttag; + var tags = []; + + if (item != null) + { + tags = $.map(item, function(tag) { + return { + id: tag.name, + name: tag.name + }; + }); + } + + args.response.success({ + data: tags, + hintText: _l('hint.type.part.host.tag'), + noResultsText: _l('hint.no.host.tags') + }); + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + + args.response.error(errorMsg); + } + }); + } + } + //always appear (end) + } + }, + + action: function (args) { + var data = { + zoneid: args.data.zoneid, + podid: args.data.podId, + clusterid: args.data.clusterId, + hypervisor: selectedClusterObj.hypervisortype, + clustertype: selectedClusterObj.clustertype, + hosttags: args.data.hosttags + }; + + if (selectedClusterObj.hypervisortype == "VMware") { + $.extend(data, { + username: '', + password: '' + }); + + var hostname = args.data.vcenterHost; + var url; + if (hostname.indexOf("http://") == -1) + url = "http://" + hostname; else + url = hostname; + + $.extend(data, { + url: url + }); + } else { + $.extend(data, { + username: args.data.username, + password: args.data.password + }); + + var hostname = args.data.hostname; + var url; + if (hostname.indexOf("http://") == -1) + url = "http://" + hostname; else + url = hostname; + + $.extend(data, { + url: url + }); + + if (selectedClusterObj.hypervisortype == "BareMetal") { + $.extend(data, { + cpunumber: args.data.baremetalCpuCores, + cpuspeed: args.data.baremetalCpu, + memory: args.data.baremetalMemory, + hostmac: args.data.baremetalMAC + }); + } else if (selectedClusterObj.hypervisortype == "Ovm") { + $.extend(data, { + agentusername: args.data.agentUsername, + agentpassword: args.data.agentPassword + }); + } else if (selectedClusterObj.hypervisortype == "Ovm3") { + $.extend(data, { + agentusername: args.data.agentUsername, + agentpassword: args.data.agentPassword, + agentport: args.data.agentPort + }); + } + } + + var hostId = null; + $.ajax({ + url: createURL("addHost"), + type: "POST", + data: data, + success: function (json) { + var item = json.addhostresponse.host[0]; + + hostId = json.addhostresponse.host[0].id; + + //EXPLICIT DEDICATION + var array2 =[]; + + if (args.$form.find('.form-item[rel=isDedicated]').find('input[type=checkbox]').is(':Checked') == true) { + if (args.data.accountId != "") + array2.push("&account=" + encodeURIComponent(args.data.accountId)); + + + if (hostId != null) { + $.ajax({ + url: createURL("dedicateHost&hostId=" + hostId + "&domainId=" + args.data.domainId + array2.join("")), + dataType: "json", + success: function (json) { + var jid = json.dedicatehostresponse.jobid; + args.response.success({ + _custom: { + jobId: jid + }, + notification: { + poll: pollAsyncJobResult, + interval: 4500, + desc: "Dedicate Host" + }, + + data: item + }); + }, + + error: function (json) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + } + } + args.response.success({ + data: item + }); + }, + + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + }, + + notification: { + poll: function (args) { + args.complete({ + actionFilter: hostActionfilter + }); + } + }, + + messages: { + notification: function (args) { + return 'label.add.host'; + } + } + }, + viewMetrics: { + label: 'label.metrics', + isHeader: true, + addRow: false, + action: { + custom: cloudStack.uiCustom.metricsView({resource: 'hosts'}) + }, + messages: { + notification: function (args) { + return 'label.metrics'; + } + } + }, + startRollingMaintenance: rollingMaintenanceAction({ listView: true, entity: 'hosts' }) + }, + detailView: { + name: "Host details", + viewAll: { + label: 'label.instances', + path: 'instances' + }, + actions: { + startRollingMaintenance: { + label: 'label.start.rolling.maintenance', + textLabel: 'label.start.rolling.maintenance', + messages: { + notification: function (args) { + return 'label.start.rolling.maintenance'; + } + }, + createForm: { + title: 'label.start.rolling.maintenance', + fields: { + timeout: { + label: 'label.timeout', + }, + force: { + isBoolean: true, + label: 'label.start.rolling.maintenance.force' + }, + payload: { + label: 'label.start.rolling.maintenance.payload' + } + } + }, + action: function (args) { + var data = { + hostids: args.context.hosts[0].id, + force: args.data.force, + timeout: args.data.timeout, + payload: args.data.payload + }; + $.ajax({ + url: createURL("startRollingMaintenance"), + dataType: "json", + data: data, + async: true, + success: function (json) { + var item = json.rollingmaintenance; + args.response.success({ + actionFilter: zoneActionfilter, + data: item + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + edit: { + label: 'label.edit', + action: function (args) { + var array1 =[]; + array1.push("&hosttags=" + encodeURIComponent(args.data.hosttags)); + + if (args.data.oscategoryid != null && args.data.oscategoryid.length > 0) + array1.push("&osCategoryId=" + args.data.oscategoryid); + + if (args.data.annotation != null && args.data.annotation.length > 0) + array1.push("&annotation=" + args.data.annotation); + + $.ajax({ + url: createURL("updateHost&id=" + args.context.hosts[0].id + array1.join("")), + dataType: "json", + success: function (json) { + var item = json.updatehostresponse.host; + args.response.success({ + actionFilter: hostActionfilter, + data: item + }); + } + }); + } + }, + + + dedicate: { + label: 'label.dedicate.host', + messages: { + confirm: function (args) { + return 'message.confirm.dedicate.host.domain.account'; + }, + notification: function (args) { + return 'message.host.dedicated'; + } + }, + createForm: { + title: 'label.dedicate.host', + fields: { + domainId: { + label: 'label.domain', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL('listDomains'), + data: { + listAll: true, + details: 'min' + }, + dataType: "json", + async: false, + success: function (json) { + var domainObjs = json.listdomainsresponse.domain; + var items =[]; + + $(domainObjs).each(function () { + items.push({ + id: this.id, + description: this.name + }); + }); + items.sort(function(a, b) { + return a.description.localeCompare(b.description); + }); + + args.response.success({ + data: items + }); + } + }); + } + }, + accountId: { + label: 'label.account', + docID: 'helpAccountForDedication', + validation: { + required: false + } + } + } + }, + action: function (args) { + //EXPLICIT DEDICATION + var array2 =[]; + if (args.data.accountId != "") + array2.push("&account=" + encodeURIComponent(args.data.accountId)); + + $.ajax({ + url: createURL("dedicateHost&hostId=" + + args.context.hosts[0].id + + "&domainId=" + args.data.domainId + array2.join("")), + dataType: "json", + success: function (json) { + var jid = json.dedicatehostresponse.jobid; + + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + release: { + label: 'label.release.dedicated.host', + messages: { + confirm: function (args) { + return 'message.confirm.release.dedicated.host'; + }, + notification: function (args) { + return 'message.host.dedication.released'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("releaseDedicatedHost&hostid=" + args.context.hosts[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.releasededicatedhostresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + secureKVMHost: { + label: 'label.action.secure.host', + action: function(args) { + var data = { + hostid: args.context.hosts[0].id + }; + $.ajax({ + url: createURL('provisionCertificate'), + data: data, + async: true, + success: function(json) { + args.response.success({ + _custom: { + jobId: json.provisioncertificateresponse.jobid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.action.secure.host'; + }, + notification: function (args) { + return 'label.action.secure.host'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + enableMaintenanceMode: { + label: 'label.action.enable.maintenance.mode', + action: function (args) { + $.ajax({ + url: createURL("prepareHostForMaintenance&id=" + args.context.hosts[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.preparehostformaintenanceresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.host; + }, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.action.host.enable.maintenance.mode'; + }, + notification: function (args) { + return 'label.action.enable.maintenance.mode'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + cancelMaintenanceMode: { + label: 'label.action.cancel.maintenance.mode', + action: function (args) { + $.ajax({ + url: createURL("cancelHostMaintenance&id=" + args.context.hosts[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.cancelhostmaintenanceresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.host; + }, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.action.cancel.maintenance.mode'; + }, + notification: function (args) { + return 'label.action.cancel.maintenance.mode'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + forceReconnect: { + label: 'label.action.force.reconnect', + action: function (args) { + $.ajax({ + url: createURL("reconnectHost&id=" + args.context.hosts[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.reconnecthostresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.host; + }, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.action.force.reconnect'; + }, + notification: function (args) { + return 'label.action.force.reconnect'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + enable: { + label: 'label.enable.host', + action: function (args) { + var data = { + id: args.context.hosts[0].id, + allocationstate: "Enable" + }; + $.ajax({ + url: createURL("updateHost"), + data: data, + success: function (json) { + var item = json.updatehostresponse.host; + args.response.success({ + actionFilter: hostActionfilter, + data: item + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.host'; + }, + notification: function (args) { + return 'label.enable.host'; + } + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + disable: { + label: 'label.disable.host', + action: function (args) { + var data = { + id: args.context.hosts[0].id, + allocationstate: "Disable" + }; + $.ajax({ + url: createURL("updateHost"), + data: data, + success: function (json) { + var item = json.updatehostresponse.host; + args.response.success({ + actionFilter: hostActionfilter, + data: item + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.host'; + }, + notification: function (args) { + return 'label.disable.host'; + } + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + 'remove': { + label: 'label.action.remove.host', + messages: { + notification: function (args) { + return 'label.action.remove.host'; + } + }, + createForm: { + title: 'label.action.remove.host', + desc: 'message.action.remove.host', + preFilter: function(args) { //bug to fix: preFilter is not picked up from here + if (!isAdmin()) { + args.$form.find('.form-item[rel=isForced]').hide(); + } + }, + fields: { + isForced: { + label: 'force.remove', + isBoolean: true, + isHidden: false + } + } + }, + action: function (args) { + var data = { + id: args.context.hosts[0].id + }; + if(args.$form.find('.form-item[rel=isForced]').css("display") != "none") { + $.extend(data, { + forced: (args.data.isForced == "on") + }); + } + + $.ajax({ + url: createURL("deleteHost"), + data: data, + success: function (json) { + //{ "deletehostresponse" : { "success" : "true"} } + args.response.success({ + data: { + } + }); + + if (args.context.hosts[0].hypervisor == "XenServer") { + cloudStack.dialog.notice({ message: _s("The host has been removed. Please eject the host from the XenServer Resource Pool.") }) + } + else if (args.context.hosts[0].hypervisor == "VMware") { + cloudStack.dialog.notice({ message: _s("The host has been removed. Please eject the host from the vSphere Cluster.") }) + } + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + blankHAForHost: { + label: '', + action: function (args) { + } + }, + + configureHAForHost: { + label: 'label.ha.configure', + messages: { + confirm: function (args) { + return 'label.ha.configure'; + }, + notification: function (args) { + return 'label.ha.configure'; + } + }, + createForm: { + title: 'label.ha.configure', + fields: { + provider: { + label: 'label.ha.provider', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL('listHostHAProviders'), + data: {'hypervisor': args.context.hosts[0].hypervisor}, + dataType: 'json', + success: function (json) { + var response = json.listhosthaprovidersresponse; + var items = []; + items.push({ + id: '', + description: _l('') + }); + if (response.haprovider) { + $.each(response.haprovider, function (idx, item) { + items.push({ + id: item.haprovider, + description: item.haprovider + }); + }); + } + args.response.success({ + data: items + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + } + }, + action: function (args) { + var data = args.data; + data.hostid = args.context.hosts[0].id; + $.ajax({ + url: createURL('configureHAForHost'), + data: data, + dataType: 'json', + success: function (json) { + var jid = json.configurehaforhostresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + enableHA: { + label: 'label.ha.enable', + action: function (args) { + var data = { + hostid: args.context.hosts[0].id, + }; + $.ajax({ + url: createURL("enableHAForHost"), + data: data, + success: function (json) { + var jid = json.enablehaforhostresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'label.ha.enable'; + }, + notification: function (args) { + return 'label.ha.enable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + disableHA: { + label: 'label.ha.disable', + action: function (args) { + var data = { + hostid: args.context.hosts[0].id, + }; + $.ajax({ + url: createURL("disableHAForHost"), + data: data, + success: function (json) { + var jid = json.disablehaforhostresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'label.ha.disable'; + }, + notification: function (args) { + return 'label.ha.disable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + blankOutOfBandManagement: { + label: '', + action: function (args) { + } + }, + + configureOutOfBandManagement: { + label: 'label.outofbandmanagement.configure', + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.configure'; + }, + notification: function (args) { + return 'message.outofbandmanagement.configure'; + } + }, + createForm: { + title: 'label.outofbandmanagement.configure', + fields: { + address: { + label: 'label.outofbandmanagement.address', + validation: { + required: true + } + }, + port: { + label: 'label.outofbandmanagement.port', + validation: { + required: true + } + }, + username: { + label: 'label.outofbandmanagement.username', + validation: { + required: false + } + }, + password: { + label: 'label.outofbandmanagement.password', + isPassword: true, + validation: { + required: false + }, + }, + driver: { + label: 'label.outofbandmanagement.driver', + validation: { + required: true + }, + select: function (args) { + var oobm = args.context.hosts[0].outofbandmanagement; + if (oobm) { + args.$form.find('input[name=address]').val(oobm.address); + args.$form.find('input[name=port]').val(oobm.port); + args.$form.find('input[name=username]').val(oobm.username); + + args.$form.find('input[name=address]').change(function() { + $this.find('input[name=address]').val(oobm.address); + }); + } + + var items = []; + items.push({ + id: 'ipmitool', + description: 'ipmitool - ipmitool based shell driver' + }); + items.push({ + id: 'nestedcloudstack', + description: 'nested-cloudstack - controls host that is a VM in a parent cloudstack (testing purposes only)' + }); + args.response.success({ + data: items + }); + } + } + } + }, + action: function (args) { + var data = args.data; + data.hostid = args.context.hosts[0].id; + + $.ajax({ + url: createURL('configureOutOfBandManagement'), + data: data, + dataType: 'json', + success: function (json) { + var response = json.configureoutofbandmanagementresponse; + args.response.success({ + actionFilter: hostActionfilter, + data: response + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + enableOutOfBandManagement: { + label: 'label.outofbandmanagement.enable', + action: function (args) { + var data = { + hostid: args.context.hosts[0].id, + }; + $.ajax({ + url: createURL("enableOutOfBandManagementForHost"), + data: data, + success: function (json) { + var jid = json.enableoutofbandmanagementforhostresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.enable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.enable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + disableOutOfBandManagement: { + label: 'label.outofbandmanagement.disable', + action: function (args) { + var data = { + hostid: args.context.hosts[0].id, + }; + $.ajax({ + url: createURL("disableOutOfBandManagementForHost"), + data: data, + success: function (json) { + var jid = json.disableoutofbandmanagementforhostresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + + }); + }, + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.disable'; + }, + notification: function (args) { + return 'message.outofbandmanagement.disable'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + issueOutOfBandManagementPowerAction: { + label: 'label.outofbandmanagement.action.issue', + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.issue'; + }, + notification: function (args) { + return 'message.outofbandmanagement.issue'; + } + }, + createForm: { + title: 'label.outofbandmanagement.action.issue', + desc: function(args) { + var host = args.context.hosts[0]; + if (host.resourcestate == 'Maintenance' || host.resourcestate == 'PrepareForMaintenance' || + host.resourcestate == 'ErrorInPrepareForMaintenance' || host.resourcestate == 'ErrorInMaintenance') { + return _l('message.outofbandmanagement.action.maintenance'); + } + }, + fields: { + action: { + label: 'label.outofbandmanagement.action', + validation: { + required: true + }, + select: function (args) { + var items = []; + items.push({ + id: 'ON', + description: 'ON - turn on host' + }); + items.push({ + id: 'OFF', + description: 'OFF - turn off host' + }); + items.push({ + id: 'CYCLE', + description: 'CYCLE - power cycle the host' + }); + items.push({ + id: 'RESET', + description: 'RESET - power reset the host' + }); + items.push({ + id: 'SOFT', + description: 'SOFT - soft shutdown the host using ACPI etc' + }); + items.push({ + id: 'STATUS', + description: 'STATUS - update power status of the host' + }); + args.response.success({ + data: items + }); + } + }, + } + }, + action: function (args) { + var data = args.data; + data.hostid = args.context.hosts[0].id; + $.ajax({ + url: createURL('issueOutOfBandManagementPowerAction'), + data: data, + dataType: 'json', + success: function (json) { + var jid = json.issueoutofbandmanagementpoweractionresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + changeOutOfBandManagementPassword: { + label: 'label.outofbandmanagement.changepassword', + messages: { + confirm: function (args) { + return 'message.outofbandmanagement.changepassword'; + }, + notification: function (args) { + return 'message.outofbandmanagement.changepassword'; + } + }, + createForm: { + title: 'label.outofbandmanagement.changepassword', + fields: { + password: { + label: 'label.outofbandmanagement.password', + isPassword: true, + validation: { + required: false + }, + }, + reenterpassword: { + label: 'label.outofbandmanagement.reenterpassword', + isPassword: true, + validation: { + required: false + } + }, + } + }, + action: function (args) { + var data = args.data; + if (data.password != data.reenterpassword) { + args.response.error("Passwords do not match"); + return; + } + data.hostid = args.context.hosts[0].id; + $.ajax({ + url: createURL('changeOutOfBandManagementPassword'), + data: data, + dataType: 'json', + success: function (json) { + var jid = json.changeoutofbandmanagementpasswordresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getActionFilter: function () { + return hostActionfilter; + } + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + + }, + tabFilter: function (args) { + var hiddenTabs =[]; + var host = args.context.hosts[0]; + if (host.gpugroup == null) { + hiddenTabs.push("gpu"); + } + if (host.outofbandmanagement == null || !host.outofbandmanagement.enabled) { + hiddenTabs.push("outofbandmanagement"); + } + if (host.hostha == null || (host.hypervisor != 'KVM' && host.hypervisor != 'Simulator')) { + hiddenTabs.push("ha"); + } + return hiddenTabs; + }, + tabs: { + details: { + title: 'label.details', + + preFilter: function (args) { + var hiddenFields =[]; + $.ajax({ + url: createURL('listConfigurations&name=ha.tag'), + dataType: 'json', + async: false, + success: function (json) { + if (json.listconfigurationsresponse.configuration == null || json.listconfigurationsresponse.configuration[0].value == null || json.listconfigurationsresponse.configuration[0].value.length == 0) { + hiddenFields.push('hahost'); + } + } + }); + return hiddenFields; + }, + + fields:[ { + name: { + label: 'label.name' + } + }, + { + id: { + label: 'label.id' + }, + resourcestate: { + label: 'label.resource.state' + }, + state: { + label: 'label.state' + }, + powerstate: { + label: 'label.powerstate' + }, + type: { + label: 'label.type' + }, + hypervisor: { + label: 'label.hypervisor' + }, + hypervisorversion: { + label: 'label.hypervisor.version' + }, + hastate: { + label: 'label.ha.state' + }, + haprovider: { + label: 'label.ha.provider' + }, + hosttags: { + label: 'label.host.tags', + isEditable: true, + isTokenInput: true, + dataProvider: function(args) { + $.ajax({ + url: createURL("listHostTags"), + dataType: "json", + success: function(json) { + var item = json.listhosttagsresponse.hosttag; + var tags = []; + + if (item != null) + { + tags = $.map(item, function(tag) { + return { + id: tag.name, + name: tag.name + }; + }); + } + + args.response.success({ + data: tags, + hintText: _l('hint.type.part.host.tag'), + noResultsText: _l('hint.no.host.tags') + }); + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + + args.response.error(errorMsg); + } + }); + } + }, + ueficapability: { + label:'label.host.ueficapability', + converter: cloudStack.converters.toBooleanText + }, + hahost: { + label: 'label.ha.enabled', + converter: cloudStack.converters.toBooleanText + }, + oscategoryid: { + label: 'label.os.preference', + isEditable: true, + select: function (args) { + $.ajax({ + url: createURL("listOsCategories"), + dataType: "json", + async: true, + success: function (json) { + var oscategoryObjs = json.listoscategoriesresponse.oscategory; + var items =[ { + id: '', + description: _l('') + }]; + $(oscategoryObjs).each(function () { + items.push({ + id: this.id, + description: this.name + }); + }); + args.response.success({ + data: items + }); + } + }); + } + }, + zonename: { + label: 'label.zone' + }, + podname: { + label: 'label.pod' + }, + clustername: { + label: 'label.cluster' + }, + ipaddress: { + label: 'label.ip.address' + }, + annotation: { + label: 'label.annotation', + isEditable: true + }, + lastannotated: { + label: 'label.last.annotated', + converter: cloudStack.converters.toLocalDate + }, + username: { + label: 'label.annotated.by' + }, + disconnected: { + label: 'label.last.disconnected' + }, + cpusockets: { + label: 'label.number.of.cpu.sockets' + }, + managementServers: { + label: 'label.number.of.management.servers' + } + }, { + + isdedicated: { + label: 'label.dedicated' + }, + domainid: { + label: 'label.domain.id' + } + }], + + dataProvider: function (args) { + $.ajax({ + url: createURL("listHosts&id=" + args.context.hosts[0].id), + dataType: "json", + async: true, + success: function (json) { + var item = json.listhostsresponse.host[0]; + if (item && item.outofbandmanagement) { + item.powerstate = item.outofbandmanagement.powerstate; + } + + if (!item.hypervisorversion && item.details && item.details["Host.OS"]) { + item.hypervisorversion = item.details["Host.OS"] + " " + item.details["Host.OS.Version"]; + } + + if (item && item.hostha) { + item.hastate = item.hostha.hastate; + item.haprovider = item.hostha.haprovider; + item.haenabled = item.hostha.haenable; + } + + item.annotation = item.annotation; + item.lastannotated = item.lastannotated; + item.username = item.username; + + $.ajax({ + url: createURL("listDedicatedHosts&hostid=" + args.context.hosts[0].id), + dataType: "json", + async: false, + success: function (json) { + if (json.listdedicatedhostsresponse.dedicatedhost != undefined) { + var hostItem = json.listdedicatedhostsresponse.dedicatedhost[0]; + if (hostItem.domainid != null) { + $.extend(item, { + isdedicated: _l('label.yes'), + domainid: hostItem.domainid + }); + } + } else + $.extend(item, { + isdedicated: _l('label.no') + }) + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + args.response.success({ + actionFilter: hostActionfilter, + data: item + }); + } + }); + } + }, + + ha: { + title: 'label.ha', + fields: { + haenable: { + label: 'label.ha.enabled', + converter: cloudStack.converters.toBooleanText + }, + hastate: { + label: 'label.ha.state' + }, + haprovider: { + label: 'label.ha.provider' + }, + }, + dataProvider: function (args) { + $.ajax({ + url: createURL("listHosts&id=" + args.context.hosts[0].id), + dataType: "json", + async: true, + success: function (json) { + var host = json.listhostsresponse.host[0]; + var hostha = {}; + if (host && host.hostha) { + hostha = host.hostha; + } + args.response.success({ + data: hostha + }); + } + }); + } + }, + + outofbandmanagement: { + title: 'label.outofbandmanagement', + fields: { + powerstate: { + label: 'label.powerstate' + }, + driver: { + label: 'label.outofbandmanagement.driver' + }, + username: { + label: 'label.outofbandmanagement.username' + }, + address: { + label: 'label.outofbandmanagement.address' + }, + port: { + label: 'label.outofbandmanagement.port' + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL("listHosts&id=" + args.context.hosts[0].id), + dataType: "json", + async: true, + success: function (json) { + var host = json.listhostsresponse.host[0]; + var oobm = {}; + if (host && host.outofbandmanagement) { + oobm = host.outofbandmanagement; + } + args.response.success({ + data: oobm + }); + } + }); + } + }, + + stats: { + title: 'label.statistics', + fields: { + totalCPU: { + label: 'label.total.cpu' + }, + cpuused: { + label: 'label.cpu.utilized' + }, + cpuallocated: { + label: 'label.cpu.allocated.for.VMs' + }, + memorytotal: { + label: 'label.memory.total' + }, + memoryallocated: { + label: 'label.memory.allocated' + }, + memoryused: { + label: 'label.memory.used' + }, + networkkbsread: { + label: 'label.network.read' + }, + networkkbswrite: { + label: 'label.network.write' + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL("listHosts&id=" + args.context.hosts[0].id), + dataType: "json", + async: true, + success: function (json) { + var jsonObj = json.listhostsresponse.host[0]; + args.response.success({ + data: { + totalCPU: jsonObj.cpunumber + " x " + cloudStack.converters.convertHz(jsonObj.cpuspeed), + cpuused: jsonObj.cpuused, + cpuallocated: (jsonObj.cpuallocated == null || jsonObj.cpuallocated == 0) ? "N/A": jsonObj.cpuallocated, + memorytotal: (jsonObj.memorytotal == null || jsonObj.memorytotal == 0) ? "N/A": cloudStack.converters.convertBytes(jsonObj.memorytotal), + memoryallocated: (jsonObj.memoryallocated == null || jsonObj.memoryallocated == 0) ? "N/A": cloudStack.converters.convertBytes(jsonObj.memoryallocated), + memoryused: (jsonObj.memoryused == null || jsonObj.memoryused == 0) ? "N/A": cloudStack.converters.convertBytes(jsonObj.memoryused), + networkkbsread: (jsonObj.networkkbsread == null) ? "N/A": cloudStack.converters.convertBytes(jsonObj.networkkbsread * 1024), + networkkbswrite: (jsonObj.networkkbswrite == null) ? "N/A": cloudStack.converters.convertBytes(jsonObj.networkkbswrite * 1024) + } + }); + } + }); + } + }, + gpu: { + title: 'label.gpu', + custom: function (args) { + var gpugroups = null; + $.ajax({ + url: createURL("listHosts&id=" + args.context.hosts[0].id), + dataType: "json", + async: false, + success: function (json) { + var item = json.listhostsresponse.host[0]; + if (item != null && item.gpugroup != null) + gpugroups = item.gpugroup; + } + }); + + var $tabcontent = $('
    ').addClass('gpugroups'); + + $(gpugroups).each(function() { + var gpugroupObj = this; + + var $groupcontainer = $('
    ').addClass('gpugroup-container'); + + //group name + $groupcontainer.append($('
    ').addClass('title') + .append($('').html(gpugroupObj.gpugroupname))); + //vgpu details + var $groupdetails = $('
    ').listView({ + context: args.context, + listView: { + id: 'gputypes', + hideToolbar: true, + fields: { + vgputype: { + label: 'label.vgpu.type' + }, + maxvgpuperpgpu: { + label: 'label.vgpu.max.vgpu.per.gpu', + converter: function (args) { + return (args == null || args == 0) ? "" : args; + } + }, + videoram: { + label: 'label.vgpu.video.ram', + converter: function (args) { + return (args == null || args == 0) ? "" : cloudStack.converters.convertBytes(args); + } + }, + maxresolution: { + label: 'label.vgpu.max.resolution' + }, + remainingcapacity: { + label: 'label.vgpu.remaining.capacity' + } + }, + dataProvider: function (args) { + var items; + + if(typeof(gpugroupObj.vgpu) != "undefined") { + items = gpugroupObj.vgpu.sort(function(a, b) { + return a.maxvgpuperpgpu >= b.maxvgpuperpgpu; + }); + } + else { + items = gpugroupObj.vgpu; + } + $(items).each(function () { + this.maxresolution = (this.maxresolutionx == null || this.maxresolutionx == 0 + || this.maxresolutiony == null || this.maxresolutiony == 0) + ? "" : this.maxresolutionx + " x " + this.maxresolutiony; + }); + args.response.success({ + data: items + }); + } + } + }); + $groupcontainer.append($groupdetails); + $tabcontent.append($groupcontainer); + }); + return $tabcontent; + } + } + } + } + } + }, + 'primary-storage': { + title: 'label.primary.storage', + id: 'primarystorages', + listView: { + id: 'primarystorages', + section: 'primary-storage', + fields: { + name: { + label: 'label.name', + truncate: true + }, + ipaddress: { + label: 'label.server' + }, + path: { + label: 'label.path', + truncate: true + }, + type: { + label: 'label.type' + }, + scope: { + label: 'label.scope' + }, + clustername: { + label: 'label.cluster', + truncate: true + }, + zonename: { + label: 'label.zone' + }, + state: { + label: 'label.state', + converter: function (str) { + // For localization + return str; + }, + indicator: { + 'Up': 'on', + 'Down': 'off', + 'Removed': 'off', + 'ErrorInMaintenance': 'off', + 'ErrorInPrepareForMaintenance': 'warning', + 'PrepareForMaintenance': 'warning', + 'CancelMaintenance': 'warning', + 'Maintenance': 'warning', + } + } + }, + + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + array1.push("&zoneid=" + args.context.zones[0].id); + if ("pods" in args.context) + array1.push("&podid=" + args.context.pods[0].id); + if ("clusters" in args.context) + array1.push("&clusterid=" + args.context.clusters[0].id); + $.ajax({ + url: createURL("listStoragePools&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + dataType: "json", + async: true, + success: function (json) { + var items = json.liststoragepoolsresponse.storagepool; + args.response.success({ + actionFilter: primarystorageActionfilter, + data: items + }); + } + }); + }, + + actions: { + add: { + label: 'label.add.primary.storage', + + createForm: { + title: 'label.add.primary.storage', + fields: { + scope: { + label: 'label.scope', + select: function (args) { + var scope =[ { + id: 'cluster', + description: _l('label.cluster') + }, + { + id: 'zone', + description: _l('label.zone.wide') + } + // { id: 'host', description: _l('label.host') } + ]; + + args.response.success({ + data: scope + }); + + args.$select.change(function () { + var $form = $(this).closest('form'); + var scope = $(this).val(); + + if (scope == 'zone') { + $form.find('.form-item[rel=podId]').hide(); + $form.find('.form-item[rel=clusterId]').hide(); + $form.find('.form-item[rel=hostId]').hide(); + $form.find('.form-item[rel=hypervisor]').css('display', 'inline-block'); + } else if (scope == 'cluster') { + + $form.find('.form-item[rel=hostId]').hide(); + $form.find('.form-item[rel=podId]').css('display', 'inline-block'); + $form.find('.form-item[rel=clusterId]').css('display', 'inline-block'); + $form.find('.form-item[rel=hypervisor]').hide(); + } else if (scope == 'host') { + $form.find('.form-item[rel=podId]').css('display', 'inline-block'); + $form.find('.form-item[rel=clusterId]').css('display', 'inline-block'); + $form.find('.form-item[rel=hostId]').css('display', 'inline-block'); + $form.find('.form-item[rel=hypervisor]').hide(); + } + }) + } + }, + + + hypervisor: { + label: 'label.hypervisor', + isHidden: true, + select: function (args) { + var items =[]; + items.push({ + id: 'KVM', + description: _l('KVM') + }); + items.push({ + id: 'VMware', + description: _l('VMware') + }); + items.push({ + id: 'Hyperv', + description: _l('Hyperv') + }); + items.push({ + id: 'Any', + description: _l('Any') + }); + args.response.success({ + data: items + }); + } + }, + + zoneid: { + label: 'label.zone', + docID: 'helpPrimaryStorageZone', + validation: { + required: true + }, + select: function (args) { + var data = args.context.zones ? { + id: args.context.zones[0].id + }: {}; + + $.ajax({ + url: createURL('listZones'), + data: data, + success: function (json) { + var zones = json.listzonesresponse.zone ? json.listzonesresponse.zone:[]; + + args.response.success({ + data: $.map(zones, function (zone) { + return { + id: zone.id, + description: zone.name + }; + }) + }); + } + }); + } + }, + podId: { + label: 'label.pod', + dependsOn: 'zoneid', + docID: 'helpPrimaryStoragePod', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL("listPods&zoneid=" + args.zoneid), + dataType: "json", + async: true, + success: function (json) { + var pods = json.listpodsresponse.pod; + var items =[]; + $(pods).each(function () { + items.push({ + id: this.id, + description: this.name + }); + }); + args.response.success({ + data: items + }); + } + }); + } + }, + + clusterId: { + label: 'label.cluster', + docID: 'helpPrimaryStorageCluster', + validation: { + required: true + }, + dependsOn: 'podId', + select: function (args) { + $.ajax({ + url: createURL("listClusters&podid=" + args.podId), + dataType: "json", + async: false, + success: function (json) { + clusterObjs = json.listclustersresponse.cluster; + var items =[]; + $(clusterObjs).each(function () { + items.push({ + id: this.id, + description: this.name + }); + }); + args.response.success({ + actionFilter: clusterActionfilter, + data: items + }); + } + }); + } + }, + + hostId: { + label: 'label.host', + validation: { + required: true + }, + dependsOn: 'clusterId', + select: function (args) { + $.ajax({ + url: createURL('listHosts'), + data: { + clusterid: args.clusterId + }, + success: function (json) { + var hosts = json.listhostsresponse.host ? + json.listhostsresponse.host:[] + args.response.success({ + data: $.map(hosts, function (host) { + return { + id: host.id, + description: host.name + } + }) + }); + } + }); + } + }, + + name: { + label: 'label.name', + docID: 'helpPrimaryStorageName', + validation: { + required: true + } + }, + + protocol: { + label: 'label.protocol', + docID: 'helpPrimaryStorageProtocol', + validation: { + required: true + }, + dependsOn: 'clusterId', + select: function (args) { + var clusterId = args.clusterId; + if (clusterId == null || clusterId.length == 0) { + args.response.success({ + data: [] + }); + return; + } + + $(clusterObjs).each(function () { + if (this.id == clusterId) { + selectedClusterObj = this; + return false; //break the $.each() loop + } + }); + + if (selectedClusterObj.hypervisortype == "KVM") { + var items =[]; + items.push({ + id: "nfs", + description: "nfs" + }); + items.push({ + id: "SharedMountPoint", + description: "SharedMountPoint" + }); + items.push({ + id: "rbd", + description: "RBD" + }); + items.push({ + id: "clvm", + description: "CLVM" + }); + items.push({ + id: "gluster", + description: "Gluster" + }); + items.push({ + id: "custom", + description: "custom" + }); + args.response.success({ + data: items + }); + } else if (selectedClusterObj.hypervisortype == "XenServer") { + var items =[]; + items.push({ + id: "nfs", + description: "nfs" + }); + items.push({ + id: "PreSetup", + description: "PreSetup" + }); + items.push({ + id: "iscsi", + description: "iscsi" + }); + items.push({ + id: "custom", + description: "custom" + }); + args.response.success({ + data: items + }); + } else if (selectedClusterObj.hypervisortype == "VMware") { + var items =[]; + items.push({ + id: "nfs", + description: "nfs" + }); + items.push({ + id: "vmfs", + description: "vmfs" + }); + items.push({ + id: "custom", + description: "custom" + }); + args.response.success({ + data: items + }); + } else if (selectedClusterObj.hypervisortype == "Hyperv") { + var items =[]; + items.push({ + id: "SMB", + description: "SMB/CIFS" + }); + args.response.success({ + data: items + }); + } else if (selectedClusterObj.hypervisortype == "Ovm") { + var items =[]; + items.push({ + id: "nfs", + description: "nfs" + }); + items.push({ + id: "ocfs2", + description: "ocfs2" + }); + args.response.success({ + data: items + }); + } else if (selectedClusterObj.hypervisortype == "LXC") { + var items =[]; + items.push({ + id: "nfs", + description: "nfs" + }); + items.push({ + id: "SharedMountPoint", + description: "SharedMountPoint" + }); + items.push({ + id: "rbd", + description: "RBD" + }); + args.response.success({ + data: items + }); + // 3.3.2 has ceph/ocfs2/iscsi etc + } else if (selectedClusterObj.hypervisortype == "Ovm3") { + var items =[]; + items.push({ + id: "nfs", + description: "nfs" + }); + } else { + args.response.success({ + data:[] + }); + } + + args.$select.change(function () { + var $form = $(this).closest('form'); + + var protocol = $(this).val(); + if (protocol == null) + return; + + + if (protocol == "nfs") { + $form.find('.form-item[rel=server]').css('display', 'inline-block'); + $form.find('.form-item[rel=server]').find(".value").find("input").val(""); + + $form.find('.form-item[rel=path]').css('display', 'inline-block'); + var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); + $form.find('.form-item[rel=path]').find(".name").find("label").text("Path:").prepend($required); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + + $form.find('.form-item[rel=iqn]').hide(); + $form.find('.form-item[rel=lun]').hide(); + + $form.find('.form-item[rel=volumegroup]').hide(); + + $form.find('.form-item[rel=vCenterDataCenter]').hide(); + $form.find('.form-item[rel=vCenterDataStore]').hide(); + + $form.find('.form-item[rel=rbdmonitor]').hide(); + $form.find('.form-item[rel=rbdpool]').hide(); + $form.find('.form-item[rel=rbdid]').hide(); + $form.find('.form-item[rel=rbdsecret]').hide(); + + $form.find('.form-item[rel=glustervolume]').hide(); + } else if (protocol == "SMB") { + //"SMB" show almost the same fields as "nfs" does, except 3 more SMB-specific fields. + $form.find('.form-item[rel=server]').css('display', 'inline-block'); + $form.find('.form-item[rel=server]').find(".value").find("input").val(""); + + $form.find('.form-item[rel=path]').css('display', 'inline-block'); + var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); + $form.find('.form-item[rel=path]').find(".name").find("label").text("Path:").prepend($required); + + $form.find('.form-item[rel=smbUsername]').css('display', 'inline-block'); + $form.find('.form-item[rel=smbPassword]').css('display', 'inline-block'); + $form.find('.form-item[rel=smbDomain]').css('display', 'inline-block'); + + $form.find('.form-item[rel=iqn]').hide(); + $form.find('.form-item[rel=lun]').hide(); + + $form.find('.form-item[rel=volumegroup]').hide(); + + $form.find('.form-item[rel=vCenterDataCenter]').hide(); + $form.find('.form-item[rel=vCenterDataStore]').hide(); + + $form.find('.form-item[rel=rbdmonitor]').hide(); + $form.find('.form-item[rel=rbdpool]').hide(); + $form.find('.form-item[rel=rbdid]').hide(); + $form.find('.form-item[rel=rbdsecret]').hide(); + + $form.find('.form-item[rel=glustervolume]').hide(); + } else if (protocol == "ocfs2") { + //ocfs2 is the same as nfs, except no server field. + $form.find('.form-item[rel=server]').hide(); + $form.find('.form-item[rel=server]').find(".value").find("input").val(""); + + $form.find('.form-item[rel=path]').css('display', 'inline-block'); + var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); + $form.find('.form-item[rel=path]').find(".name").find("label").text("Path:").prepend($required); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + + $form.find('.form-item[rel=iqn]').hide(); + $form.find('.form-item[rel=lun]').hide(); + + $form.find('.form-item[rel=volumegroup]').hide(); + + $form.find('.form-item[rel=vCenterDataCenter]').hide(); + $form.find('.form-item[rel=vCenterDataStore]').hide(); + + $form.find('.form-item[rel=rbdmonitor]').hide(); + $form.find('.form-item[rel=rbdpool]').hide(); + $form.find('.form-item[rel=rbdid]').hide(); + $form.find('.form-item[rel=rbdsecret]').hide(); + + $form.find('.form-item[rel=glustervolume]').hide(); + } else if (protocol == "PreSetup") { + $form.find('.form-item[rel=server]').hide(); + $form.find('.form-item[rel=server]').find(".value").find("input").val("localhost"); + + $form.find('.form-item[rel=path]').css('display', 'inline-block'); + var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); + $form.find('.form-item[rel=path]').find(".name").find("label").text("SR Name-Label:").prepend($required); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + + $form.find('.form-item[rel=iqn]').hide(); + $form.find('.form-item[rel=lun]').hide(); + + $form.find('.form-item[rel=volumegroup]').hide(); + + $form.find('.form-item[rel=vCenterDataCenter]').hide(); + $form.find('.form-item[rel=vCenterDataStore]').hide(); + + $form.find('.form-item[rel=rbdmonitor]').hide(); + $form.find('.form-item[rel=rbdpool]').hide(); + $form.find('.form-item[rel=rbdid]').hide(); + $form.find('.form-item[rel=rbdsecret]').hide(); + + $form.find('.form-item[rel=glustervolume]').hide(); + } else if (protocol == "custom") { + $form.find('.form-item[rel=server]').hide(); + $form.find('.form-item[rel=server]').find(".value").find("input").val("localhost"); + + $form.find('.form-item[rel=path]').hide(); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + + $form.find('.form-item[rel=iqn]').hide(); + $form.find('.form-item[rel=lun]').hide(); + + $form.find('.form-item[rel=volumegroup]').hide(); + + $form.find('.form-item[rel=vCenterDataCenter]').hide(); + $form.find('.form-item[rel=vCenterDataStore]').hide(); + + $form.find('.form-item[rel=rbdmonitor]').hide(); + $form.find('.form-item[rel=rbdpool]').hide(); + $form.find('.form-item[rel=rbdid]').hide(); + $form.find('.form-item[rel=rbdsecret]').hide(); + + $form.find('.form-item[rel=glustervolume]').hide(); + } else if (protocol == "iscsi") { + $form.find('.form-item[rel=server]').css('display', 'inline-block'); + $form.find('.form-item[rel=server]').find(".value").find("input").val(""); + + $form.find('.form-item[rel=path]').hide(); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + + $form.find('.form-item[rel=iqn]').css('display', 'inline-block'); + $form.find('.form-item[rel=lun]').css('display', 'inline-block'); + + $form.find('.form-item[rel=volumegroup]').hide(); + + $form.find('.form-item[rel=vCenterDataCenter]').hide(); + $form.find('.form-item[rel=vCenterDataStore]').hide(); + + $form.find('.form-item[rel=rbdmonitor]').hide(); + $form.find('.form-item[rel=rbdpool]').hide(); + $form.find('.form-item[rel=rbdid]').hide(); + $form.find('.form-item[rel=rbdsecret]').hide(); + + $form.find('.form-item[rel=glustervolume]').hide(); + } else if ($(this).val() == "clvm") { + $form.find('.form-item[rel=server]').hide(); + $form.find('.form-item[rel=server]').find(".value").find("input").val("localhost"); + + $form.find('.form-item[rel=path]').hide(); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + + $form.find('.form-item[rel=iqn]').hide(); + $form.find('.form-item[rel=lun]').hide(); + + $form.find('.form-item[rel=volumegroup]').css('display', 'inline-block'); + + $form.find('.form-item[rel=vCenterDataCenter]').hide(); + $form.find('.form-item[rel=vCenterDataStore]').hide(); + + $form.find('.form-item[rel=rbdmonitor]').hide(); + $form.find('.form-item[rel=rbdpool]').hide(); + $form.find('.form-item[rel=rbdid]').hide(); + $form.find('.form-item[rel=rbdsecret]').hide(); + + $form.find('.form-item[rel=glustervolume]').hide(); + } else if (protocol == "vmfs") { + $form.find('.form-item[rel=server]').css('display', 'inline-block'); + $form.find('.form-item[rel=server]').find(".value").find("input").val(""); + + $form.find('.form-item[rel=path]').hide(); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + + $form.find('.form-item[rel=iqn]').hide(); + $form.find('.form-item[rel=lun]').hide(); + + $form.find('.form-item[rel=volumegroup]').hide(); + + $form.find('.form-item[rel=vCenterDataCenter]').css('display', 'inline-block'); + $form.find('.form-item[rel=vCenterDataStore]').css('display', 'inline-block'); + + $form.find('.form-item[rel=rbdmonitor]').hide(); + $form.find('.form-item[rel=rbdpool]').hide(); + $form.find('.form-item[rel=rbdid]').hide(); + $form.find('.form-item[rel=rbdsecret]').hide(); + + $form.find('.form-item[rel=glustervolume]').hide(); + } else if (protocol == "SharedMountPoint") { + //"SharedMountPoint" show the same fields as "nfs" does. + $form.find('.form-item[rel=server]').hide(); + $form.find('.form-item[rel=server]').find(".value").find("input").val("localhost"); + + $form.find('.form-item[rel=path]').css('display', 'inline-block'); + var $required = $form.find('.form-item[rel=path]').find(".name").find("label span"); + $form.find('.form-item[rel=path]').find(".name").find("label").text("Path:").prepend($required); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + + $form.find('.form-item[rel=iqn]').hide(); + $form.find('.form-item[rel=lun]').hide(); + + $form.find('.form-item[rel=volumegroup]').hide(); + + $form.find('.form-item[rel=vCenterDataCenter]').hide(); + $form.find('.form-item[rel=vCenterDataStore]').hide(); + + $form.find('.form-item[rel=rbdmonitor]').hide(); + $form.find('.form-item[rel=rbdpool]').hide(); + $form.find('.form-item[rel=rbdid]').hide(); + $form.find('.form-item[rel=rbdsecret]').hide(); + + $form.find('.form-item[rel=glustervolume]').hide(); + } else if (protocol == "rbd") { + $form.find('.form-item[rel=rbdmonitor]').css('display', 'inline-block'); + $form.find('.form-item[rel=rbdmonitor]').find(".name").find("label").text("RADOS Monitor:"); + + $form.find('.form-item[rel=rbdpool]').css('display', 'inline-block'); + $form.find('.form-item[rel=rbdpool]').find(".name").find("label").text("RADOS Pool:"); + + $form.find('.form-item[rel=rbdid]').css('display', 'inline-block'); + $form.find('.form-item[rel=rbdid]').find(".name").find("label").text("RADOS User:"); + + $form.find('.form-item[rel=rbdsecret]').css('display', 'inline-block'); + $form.find('.form-item[rel=rbdsecret]').find(".name").find("label").text("RADOS Secret:"); + + $form.find('.form-item[rel=server]').hide(); + $form.find('.form-item[rel=iqn]').hide(); + $form.find('.form-item[rel=lun]').hide(); + $form.find('.form-item[rel=volumegroup]').hide(); + $form.find('.form-item[rel=path]').hide(); + $form.find('.form-item[rel=vCenterDataCenter]').hide(); + $form.find('.form-item[rel=vCenterDataStore]').hide(); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + + $form.find('.form-item[rel=glustervolume]').hide(); + } else if (protocol == "gluster") { + $form.find('.form-item[rel=server]').css('display', 'inline-block'); + $form.find('.form-item[rel=server]').find(".value").find("input"); + + $form.find('.form-item[rel=glustervolume]').css('display', 'inline-block'); + $form.find('.form-item[rel=glustervolume]').find(".name").find("label").text("Volume:"); + + $form.find('.form-item[rel=path]').hide(); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + + $form.find('.form-item[rel=iqn]').hide(); + $form.find('.form-item[rel=lun]').hide(); + + $form.find('.form-item[rel=volumegroup]').hide(); + + $form.find('.form-item[rel=vCenterDataCenter]').hide(); + $form.find('.form-item[rel=vCenterDataStore]').hide(); + + $form.find('.form-item[rel=rbdmonitor]').hide(); + $form.find('.form-item[rel=rbdpool]').hide(); + $form.find('.form-item[rel=rbdid]').hide(); + $form.find('.form-item[rel=rbdsecret]').hide(); + } else { + $form.find('.form-item[rel=server]').css('display', 'inline-block'); + $form.find('.form-item[rel=server]').find(".value").find("input").val(""); + + $form.find('.form-item[rel=iqn]').hide(); + $form.find('.form-item[rel=lun]').hide(); + + $form.find('.form-item[rel=volumegroup]').hide(); + + $form.find('.form-item[rel=vCenterDataCenter]').hide(); + $form.find('.form-item[rel=vCenterDataStore]').hide(); + + $form.find('.form-item[rel=rbdmonitor]').hide(); + $form.find('.form-item[rel=rbdpool]').hide(); + $form.find('.form-item[rel=rbdid]').hide(); + $form.find('.form-item[rel=rbdsecret]').hide(); + + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + + $form.find('.form-item[rel=glustervolume]').hide(); + } + }); + + args.$select.trigger("change"); + } + }, + //always appear (end) + + server: { + label: 'label.server', + docID: 'helpPrimaryStorageServer', + validation: { + required: true + }, + isHidden: true + }, + + //nfs + path: { + label: 'label.path', + docID: 'helpPrimaryStoragePath', + validation: { + required: true + }, + isHidden: true + }, + provider: { + label: 'label.provider', + validation: { + required: true + }, + select: function (args) { + var data = args.context.providers ? + { id: args.context.providers[0].id } : + {}; + + $.ajax({ + url: createURL('listStorageProviders'), + data: { + type: 'primary' + }, + success: function (json) { + var providers = json.liststorageprovidersresponse.dataStoreProvider ? json.liststorageprovidersresponse.dataStoreProvider : []; + + args.response.success({ + data: $.map(providers, function (provider) { + return { + id: provider.name, + description: provider.name + }; + }) + }); + } + }); + args.$select.change(function () { + var $form = $(this).closest('form'); + var scope = $(this).val(); + + if (scope == 'DefaultPrimary') { + $form.find('.form-item[rel=isManaged]').hide(); + $form.find('.form-item[rel=capacityIops]').hide(); + $form.find('.form-item[rel=capacityBytes]').hide(); + $form.find('.form-item[rel=url]').hide(); + } else { + $form.find('.form-item[rel=isManaged]').css('display', 'inline-block'); + $form.find('.form-item[rel=capacityIops]').css('display', 'inline-block'); + $form.find('.form-item[rel=capacityBytes]').css('display', 'inline-block'); + $form.find('.form-item[rel=url]').css('display', 'inline-block'); + } + } + ) + }}, + isManaged: { + label: 'label.managed', + docID: 'helpManaged', + isBoolean: true, + isChecked: false, + validation: { + required: false + } + }, + capacityBytes: { + label: 'label.capacity.bytes', + docID: 'helpCapacityBytes', + validation: { + required: false + } + }, + capacityIops: { + label: 'label.capacity.iops', + docID: 'helpCapacityIops', + validation: { + required: false + } + }, + url: { + label: 'label.url', + docID: 'helpUrl', + validation: { + required: false + } + }, + //SMB + smbUsername: { + label: 'label.smb.username', + validation: { + required: true + }, + isHidden: true + }, + smbPassword: { + label: 'label.smb.password', + isPassword: true, + validation: { + required: true + }, + isHidden: true + }, + smbDomain: { + label: 'label.smb.domain', + validation: { + required: true + }, + isHidden: true + }, + + //iscsi + iqn: { + label: 'label.target.iqn', + docID: 'helpPrimaryStorageTargetIQN', + validation: { + required: true + }, + isHidden: true + }, + lun: { + label: 'label.LUN.number', + docID: 'helpPrimaryStorageLun', + validation: { + required: true + }, + isHidden: true + }, + + //clvm + volumegroup: { + label: 'label.volgroup', + validation: { + required: true + }, + isHidden: true + }, + + //vmfs + vCenterDataCenter: { + label: 'label.vcenter.datacenter', + validation: { + required: true + }, + isHidden: true + }, + vCenterDataStore: { + label: 'label.vcenter.datastore', + validation: { + required: true + }, + isHidden: true + }, + + // RBD + rbdmonitor: { + label: 'label.rbd.monitor', + docID: 'helpPrimaryStorageRBDMonitor', + validation: { + required: true + }, + isHidden: true + }, + rbdpool: { + label: 'label.rbd.pool', + docID: 'helpPrimaryStorageRBDPool', + validation: { + required: true + }, + isHidden: true + }, + rbdid: { + label: 'label.rbd.id', + docID: 'helpPrimaryStorageRBDId', + validation: { + required: false + }, + isHidden: true + }, + rbdsecret: { + label: 'label.rbd.secret', + docID: 'helpPrimaryStorageRBDSecret', + validation: { + required: false + }, + isHidden: true + }, + + //gluster + glustervolume: { + label: 'label.gluster.volume', + validation: { + required: true + }, + isHidden: true + }, + + //always appear (begin) + storageTags: { + label: 'label.storage.tags', + docID: 'helpPrimaryStorageTags', + isTokenInput: true, + validation: { + required: false + }, + dataProvider: function(args) { + $.ajax({ + url: createURL("listStorageTags"), + dataType: "json", + success: function(json) { + var item = json.liststoragetagsresponse.storagetag; + var tags = []; + + if (item != null) + { + tags = $.map(item, function(tag) { + return { + id: tag.name, + name: tag.name + }; + }); + } + + args.response.success({ + data: tags, + hintText: _l('hint.type.part.storage.tag'), + noResultsText: _l('hint.no.storage.tags') + }); + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + + args.response.error(errorMsg); + } + }); + } + } + //always appear (end) + } + }, + + /******************************/ + action: function (args) { + var array1 =[]; + array1.push("&scope=" + encodeURIComponent(args.data.scope)); + + array1.push("&zoneid=" + args.data.zoneid); + + if (args.data.scope == 'zone') { + + array1.push("&hypervisor=" + args.data.hypervisor); + } + + if (args.data.scope == 'cluster') { + + array1.push("&podid=" + args.data.podId); + array1.push("&clusterid=" + args.data.clusterId); + } + + if (args.data.scope == 'host') { + array1.push("&podid=" + args.data.podId); + array1.push("&clusterid=" + args.data.clusterId); + array1.push("&hostid=" + args.data.hostId); + } + + array1.push("&name=" + encodeURIComponent(args.data.name)); + + array1.push("&provider=" + encodeURIComponent(args.data.provider)); + + if (args.data.provider == "DefaultPrimary") + { + var server = args.data.server; + var url = null; + if (args.data.protocol == "nfs") { + var path = args.data.path; + if (path.substring(0, 1) != "/") + path = "/" + path; + url = nfsURL(server, path); + } else if (args.data.protocol == "SMB") { + var path = args.data.path; + if (path.substring(0, 1) != "/") + path = "/" + path; + url = smbURL(server, path); + array1.push("&details[0].user=" + args.data.smbUsername); + array1.push("&details[1].password=" + encodeURIComponent(args.data.smbPassword)); + array1.push("&details[2].domain=" + args.data.smbDomain); + } else if (args.data.protocol == "PreSetup") { + var path = args.data.path; + if (path.substring(0, 1) != "/") + path = "/" + path; + url = presetupURL(server, path); + } else if (args.data.protocol == "ocfs2") { + var path = args.data.path; + if (path.substring(0, 1) != "/") + path = "/" + path; + url = ocfs2URL(server, path); + } else if (args.data.protocol == "SharedMountPoint") { + var path = args.data.path; + if (path.substring(0, 1) != "/") + path = "/" + path; + url = SharedMountPointURL(server, path); + } else if (args.data.protocol == "clvm") { + var vg = args.data.volumegroup; + if (vg.substring(0, 1) != "/") + vg = "/" + vg; + url = clvmURL(vg); + } else if (args.data.protocol == "rbd") { + var rbdmonitor = args.data.rbdmonitor; + var rbdpool = args.data.rbdpool; + var rbdid = args.data.rbdid; + var rbdsecret = args.data.rbdsecret; + url = rbdURL(rbdmonitor, rbdpool, rbdid, rbdsecret); + } else if (args.data.protocol == "vmfs") { + var path = args.data.vCenterDataCenter; + if (path.substring(0, 1) != "/") + path = "/" + path; + path += "/" + args.data.vCenterDataStore; + url = vmfsURL("dummy", path); + } else if (args.data.protocol == "gluster") { + var glustervolume = args.data.glustervolume; + + if (glustervolume.substring(0, 1) != "/") + glustervolume = "/" + glustervolume; + url = glusterURL(server, glustervolume); + } else if (args.data.protocol == "iscsi") { + var iqn = args.data.iqn; + if (iqn.substring(0, 1) != "/") + iqn = "/" + iqn; + var lun = args.data.lun; + url = iscsiURL(server, iqn, lun); + } else { + url = ""; + } + + array1.push("&url=" + encodeURIComponent(url)); + } + else + { + array1.push("&managed=" + (args.data.isManaged == "on").toString()); + + if (args.data.capacityBytes != null && args.data.capacityBytes.length > 0) + { + array1.push("&capacityBytes=" + args.data.capacityBytes.split(",").join("")); + } + + if (args.data.capacityIops != null && args.data.capacityIops.length > 0) + { + array1.push("&capacityIops=" + args.data.capacityIops.split(",").join("")); + } + + if (args.data.url != null && args.data.url.length > 0) + { + array1.push("&url=" + encodeURIComponent(args.data.url)); + } + } + + if (args.data.storageTags != null && args.data.storageTags.length > 0) + { + array1.push("&tags=" + encodeURIComponent(args.data.storageTags)); + } + + if ("custom" in args.response) { + args.response.custom(array1); + return; + } + + $.ajax({ + url: createURL("createStoragePool" + array1.join("")), + dataType: "json", + success: function (json) { + var item = json.createstoragepoolresponse.storagepool; + args.response.success({ + data: item + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + }, + + notification: { + poll: function (args) { + args.complete({ + actionFilter: primarystorageActionfilter + }); + } + }, + + messages: { + notification: function (args) { + return 'label.add.primary.storage'; + } + } + }, + viewMetrics: { + label: 'label.metrics', + isHeader: true, + addRow: false, + action: { + custom: cloudStack.uiCustom.metricsView({resource: 'storagepool'}) + }, + messages: { + notification: function (args) { + return 'label.metrics'; + } + } + } + }, + + detailView: { + name: "Primary storage details", + viewAll: { + label: 'label.volumes', + path: 'storage.volumes' + }, + isMaximized: true, + actions: { + edit: { + label: 'label.edit', + action: function (args) { + var array1 =[]; + array1.push("&tags=" + encodeURIComponent(args.data.tags)); + + if (args.data.disksizetotal != null && args.data.disksizetotal.length > 0) { + var diskSizeTotal = args.data.disksizetotal.split(",").join(""); + + array1.push("&capacitybytes=" + cloudStack.converters.toBytes(diskSizeTotal)); + } + + if (args.data.capacityiops != null && args.data.capacityiops.length > 0) { + var capacityIops = args.data.capacityiops.split(",").join(""); + + array1.push("&capacityiops=" + capacityIops); + } + + $.ajax({ + url: createURL("updateStoragePool&id=" + args.context.primarystorages[0].id + array1.join("")), + dataType: "json", + success: function (json) { + var item = json.updatestoragepoolresponse.storagepool; + args.response.success({ + data: item + }); + }, + error: function (XMLHttpResponse) { + args.response.error(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + } + }, + + enableMaintenanceMode: { + label: 'label.action.enable.maintenance.mode', + action: function (args) { + $.ajax({ + url: createURL("enableStorageMaintenance&id=" + args.context.primarystorages[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.prepareprimarystorageformaintenanceresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.storagepool; + }, + getActionFilter: function () { + return primarystorageActionfilter; + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.action.primarystorage.enable.maintenance.mode'; + }, + notification: function (args) { + return 'label.action.enable.maintenance.mode'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + + cancelMaintenanceMode: { + label: 'label.action.cancel.maintenance.mode', + messages: { + confirm: function (args) { + return 'message.action.cancel.maintenance.mode'; + }, + notification: function (args) { + return 'label.action.cancel.maintenance.mode'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("cancelStorageMaintenance&id=" + args.context.primarystorages[0].id), + dataType: "json", + async: true, + success: function (json) { + var jid = json.cancelprimarystoragemaintenanceresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + return json.queryasyncjobresultresponse.jobresult.storagepool; + }, + getActionFilter: function () { + return primarystorageActionfilter; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + 'remove': { + label: 'label.action.delete.primary.storage', + messages: { + notification: function (args) { + return 'label.action.delete.primary.storage'; + } + }, + createForm: { + title: 'label.action.delete.primary.storage', + fields: { + isForced: { + label: 'force.remove', + isBoolean: true + } + } + }, + action: function (args) { + var array1 =[]; + array1.push("&forced=" + (args.data.isForced == "on")); + $.ajax({ + url: createURL("deleteStoragePool&id=" + args.context.primarystorages[0].id + array1.join("")), + dataType: "json", + async: true, + success: function (json) { + args.response.success({ + data: { + } + }); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + } + }, + + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + id: { + label: 'label.id' + }, + state: { + label: 'label.state' + }, + tags: { + label: 'label.storage.tags', + isTokenInput : true, + isEditable: true, + dataProvider: function(args) { + $.ajax({ + url: createURL("listStorageTags"), + dataType: "json", + success: function(json) { + var item = json.liststoragetagsresponse.storagetag; + var tags = []; + + if (item != null) + { + tags = $.map(item, function(tag) { + return { + id: tag.name, + name: tag.name + }; + }); + } + + args.response.success({ + data: tags, + hintText: _l('hint.type.part.storage.tag'), + noResultsText: _l('hint.no.storage.tags') + }); + }, + error: function(XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + + args.response.error(errorMsg); + } + }); + } + }, + zonename: { + label: 'label.zone' + }, + podname: { + label: 'label.pod' + }, + clustername: { + label: 'label.cluster' + }, + type: { + label: 'label.type' + }, + ipaddress: { + label: 'label.ip.address' + }, + path: { + label: 'label.path' + }, + disksizetotal: { + label: 'label.disk.total', + isEditable: true, + converter: function (args) { + if (args == null || args == 0) + return ""; else + return cloudStack.converters.convertBytes(args); + } + }, + disksizeallocated: { + label: 'label.disk.allocated', + converter: function (args) { + if (args == null || args == 0) + return ""; else + return cloudStack.converters.convertBytes(args); + } + }, + capacityiops: { + label: 'label.disk.iops.total', + isEditable: true, + converter: function (args) { + if (args == null || args == 0) + return ""; else + return args; + } + }, + allocatediops: { + label: 'label.disk.iops.allocated', + isEditable: false, + converter: function (args) { + if (args == null || args == 0) + return ""; else + return args; + } + } + }], + + dataProvider: function (args) { + $.ajax({ + url: createURL("listStoragePools&id=" + args.context.primarystorages[0].id), + dataType: "json", + async: true, + success: function (json) { + var item = json.liststoragepoolsresponse.storagepool[0]; + args.response.success({ + actionFilter: primarystorageActionfilter, + data: item + }); + } + }); + } + }, + + // Granular settings for storage pool + settings: { + title: 'label.settings', + custom: cloudStack.uiCustom.granularSettings({ + dataProvider: function (args) { + + $.ajax({ + url: createURL('listConfigurations&storageid=' + args.context.primarystorages[0].id), + data: listViewDataProvider(args, { + }, + { + searchBy: 'name' + }), + success: function (json) { + args.response.success({ + data: json.listconfigurationsresponse.configuration + }); + }, + + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + actions: { + edit: function (args) { + // call updateStorageLevelParameters + var data = { + name: args.data.jsonObj.name, + value: args.data.value + }; + + $.ajax({ + url: createURL('updateConfiguration&storageid=' + args.context.primarystorages[0].id), + data: data, + success: function (json) { + var item = json.updateconfigurationresponse.configuration; + args.response.success({ + data: item + }); + }, + + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + }) + } + } + } + } + }, + + ucs: { + title: 'UCS', + id: 'ucs', + listView: { + id: 'ucsManagers', + fields: { + name: { + label: 'label.name' + }, + url: { + label: 'label.url' + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL('listUcsManagers'), + data: { + zoneid: args.context.physicalResources[0].id + }, + success: function (json) { + //for testing only (begin) + /* + json = + { + "listucsmanagerreponse": { + "count": 1, + "ucsmanager": [ + { + "id": "07b5b813-83ed-4859-952c-c95cafb63ac4", + "name": "ucsmanager", + "url": "10.223.184.2", + "zoneid": "54c9a65c-ba89-4380-96e9-1d429c5372e3" + } + ] + } + }; + */ + //for testing only (end) + + var items = json.listucsmanagerreponse.ucsmanager; + args.response.success({ + data: items + }); + } + }); + }, + actions: { + add: { + label: 'label.add.ucs.manager', + + messages: { + notification: function (args) { + return 'label.add.ucs.manager'; + } + }, + + createForm: { + title: 'label.add.ucs.manager', + fields: { + name: { + label: 'label.name', + validation: { + required: false + } + }, + url: { + label: 'label.ip', //CLOUDSTACK-4629 + validation: { + required: true + } + }, + username: { + label: 'label.username', + validation: { + required: true + } + }, + password: { + label: 'label.password', + isPassword: true, + validation: { + required: true + } + } + } + }, + + action: function (args) { + var data = { + zoneid: args.context.physicalResources[0].id, + url: args.data.url, + username: args.data.username, + password: args.data.password + }; + if (args.data.name != null && args.data.name.length > 0) { + $.extend(data, { + name: args.data.name + }); + } + + $.ajax({ + url: createURL('addUcsManager'), + data: data, + type: "POST", + success: function (json) { + //e.g. json == { "addUcsManagerResponse" : { "ucsmanager" : {"id":"11","name":"ucsmanager","url":"10.223.184.2","zoneid":"2"} } } + var item = json.addUcsManagerResponse.ucsmanager; + args.response.success({ + data: item + }); + }, + error: function (data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + + notification: { + poll: function (args) { + args.complete(); + } + } + } + }, + + detailView: { + isMaximized: true, + noCompact: true, + actions: { + remove: { + label: 'label.delete.ucs.manager', + messages: { + confirm: function (args) { + return 'message.confirm.delete.ucs.manager'; + }, + notification: function (args) { + return 'label.delete.ucs.manager'; + } + }, + action: function (args) { + var data = { + ucsmanagerid: args.context.ucsManagers[0].id + }; + $.ajax({ + url: createURL('deleteUcsManager'), + data: data, + success: function (json) { + args.response.success(); + }, + error: function (data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + } + }, + tabs: { + details: { + title: 'label.details', + + fields:[ { + name: { + label: 'label.name' + } + }, + { + id: { + label: 'label.id' + }, + url: { + label: 'label.url' + } + }], + + dataProvider: function (args) { + $.ajax({ + url: createURL('listUcsManagers'), + data: { + id: args.context.ucsManagers[0].id + }, + success: function (json) { + //for testing only (begin) + /* + json = + { + "listucsmanagerreponse": { + "count": 1, + "ucsmanager": [ + { + "id": "07b5b813-83ed-4859-952c-c95cafb63ac4", + "name": "ucsmanager", + "url": "10.223.184.2", + "zoneid": "54c9a65c-ba89-4380-96e9-1d429c5372e3" + } + ] + } + }; + */ + //for testing only (end) + + var item = json.listucsmanagerreponse.ucsmanager[0]; + args.response.success({ + data: item + }); + } + }); + } + }, + + blades: { + title: 'label.blades', + listView: { + id: 'blades', + hideSearchBar: true, + fields: { + chassis: { + label: 'label.chassis' + }, + bladeid: { + label: 'label.blade.id' + }, + profiledn: { + label: 'label.associated.profile' + } + }, + dataProvider: function (args) { + $.ajax({ + url: createURL('listUcsBlades'), + data: { + ucsmanagerid: args.context.ucsManagers[0].id + }, + success: function (json) { + //for testing only (begin) + /* + json = { + "listucsbladeresponse": { + "count": 4, + "ucsblade": [ + { + "id": "84edb958-cf8a-4e71-99c6-190ccc3fe2bd", + "ucsmanagerid": "07b5b813-83ed-4859-952c-c95cafb63ac4", + "bladedn": "sys/chassis-1/blade-1", + "profiledn": "org-root/ls-profile-for-blade-1" + }, + { + "id": "524a3e55-5b61-4561-9464-1b19e3543189", + "ucsmanagerid": "07b5b813-83ed-4859-952c-c95cafb63ac4", + "bladedn": "sys/chassis-1/blade-2", + "profiledn": "org-root/ls-profile-for-blade-2" + }, + { + "id": "4828f560-6191-46e6-8a4c-23d1d7d017f0", + "ucsmanagerid": "07b5b813-83ed-4859-952c-c95cafb63ac4", + "bladedn": "sys/chassis-1/blade-3" + }, + { + "id": "80ab25c8-3dcf-400e-8849-84dc5e1e6594", + "ucsmanagerid": "07b5b813-83ed-4859-952c-c95cafb63ac4", + "bladedn": "sys/chassis-1/blade-4" + } + ] + } + }; + */ + //for testing only (end) + + var items = json.listucsbladeresponse.ucsblade ? json.listucsbladeresponse.ucsblade:[]; + for (var i = 0; i < items.length; i++) { + addExtraPropertiesToUcsBladeObject(items[i]); + } + args.response.success({ + actionFilter: bladeActionfilter, + data: items + }); + } + }); + }, + actions: { + refreshUcsBlades: { + isHeader: true, + label: 'label.refresh.blades', + messages: { + confirm: function (args) { + return 'message.confirm.refresh.blades'; + }, + notification: function (args) { + return 'label.refresh.blades'; + } + }, + action: function (args) { + $.ajax({ + url: createURL('refreshUcsBlades'), + data: { + ucsmanagerid: args.context.ucsManagers[0].id + }, + success: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + }, + + associateTemplateToBlade: { + label: 'label.instanciate.template.associate.profile.blade', + addRow: 'false', + messages: { + notification: function (args) { + return 'label.instanciate.template.associate.profile.blade'; + } + }, + createForm: { + title: 'label.instanciate.template.associate.profile.blade', + fields: { + templatedn: { + label: 'label.select.template', + select: function (args) { + var items =[]; + + $.ajax({ + url: createURL('listUcsTemplates'), + data: { + ucsmanagerid: args.context.ucsManagers[0].id + }, + async: false, + success: function (json) { + //for testing only (begin) + /* + json = { + "listucstemplatesresponse": { + "count": 1, + "ucstemplate": [ + { + "ucsdn": "org-root/ls-test" + } + ] + } + }; + */ + //for testing only (end) + + var ucstemplates = json.listucstemplatesresponse.ucstemplate; + if (ucstemplates != null) { + for (var i = 0; i < ucstemplates.length; i++) { + items.push({ + id: ucstemplates[i].ucsdn, + description: ucstemplates[i].ucsdn + }); + } + } + } + }); + + args.response.success({ + data: items + }); + }, + validation: { + required: true + } + }, + profilename: { + label: 'label.profile' + } + } + }, + action: function (args) { + var data = { + ucsmanagerid: args.context.ucsManagers[0].id, + templatedn: args.data.templatedn, + bladeid: args.context.blades[0].id + }; + + if (args.data.profilename != null && args.data.profilename.length > 0) { + $.extend(data, { + profilename: args.data.profilename + }); + } + + $.ajax({ + url: createURL('instantiateUcsTemplateAndAssocaciateToBlade'), + data: data, + success: function (json) { + //for testing only (begin) + /* + json = { + "instantiateucstemplateandassociatetobladeresponse": { + "jobid": "cd9d0282-4dae-463f-80b6-451e168e2e92" + } + } + */ + //for testing only (end) + + var jid = json.instantiateucstemplateandassociatetobladeresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + //for testing only (begin) + /* + json = { + "queryasyncjobresultresponse": { + "accountid": "970b694a-2f8c-11e3-a77d-000c29b36ff5", + "userid": "970b7b4f-2f8c-11e3-a77d-000c29b36ff5", + "cmd": "org.apache.cloudstack.api.InstantiateUcsTemplateAndAssociateToBladeCmd", + "jobstatus": 1, + "jobprocstatus": 0, + "jobresultcode": 0, + "jobresulttype": "object", + "jobresult": { + "ucsblade": { + "id": "3d491c6e-f0b6-40b0-bf6e-f89efdd73c30", + "ucsmanagerid": "9a34c186-12fa-4bbc-af04-5f1a2bf7ae4a", + "bladedn": "sys/chassis-1/blade-3", + "profiledn": "org-root/ls-xxxx" + } + }, + "created": "2013-10-10T17:29:00-0700", + "jobid": "cd9d0282-4dae-463f-80b6-451e168e2e92" + } + }; + */ + //for testing only (end) + + addExtraPropertiesToUcsBladeObject(json.queryasyncjobresultresponse.jobresult.ucsblade); + return json.queryasyncjobresultresponse.jobresult.ucsblade; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + }, + + disassociateProfileFromBlade: { + label: 'label.disassociate.profile.blade', + addRow: 'false', + messages: { + notification: function (args) { + return 'label.disassociate.profile.blade'; + } + }, + createForm: { + title: 'label.disassociate.profile.blade', + fields: { + deleteprofile: { + label: 'label.delete.profile', + isBoolean: true, + isChecked: true + } + } + }, + action: function (args) { + $.ajax({ + url: createURL('disassociateUcsProfileFromBlade'), + data: { + bladeid: args.context.blades[0].id, + deleteprofile: (args.data.deleteprofile == 'on' ? true: false) + }, + success: function (json) { + //for testing only (begin) + /* + json = { + "disassociateucsprofilefrombladeresponse": { + "jobid": "e371592e-31be-4e53-9346-a5c565d420df" + } + } + */ + //for testing only (end) + + var jid = json.disassociateucsprofilefrombladeresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + //for testing only (begin) + /* + json = { + "queryasyncjobresultresponse": { + "accountid": "835fb2d5-0b76-11e3-9350-f4f3e49b5dfe", + "userid": "835fc0e5-0b76-11e3-9350-f4f3e49b5dfe", + "cmd": "org.apache.cloudstack.api.DisassociateUcsProfileCmd", + "jobstatus": 1, + "jobprocstatus": 0, + "jobresultcode": 0, + "jobresulttype": "object", + "jobresult": { + "ucsblade": { + "id": "f8d08575-7a1c-4f79-a588-d129c38bcc4f", + "ucsmanagerid": "0d87c1a6-5664-425c-9024-2ddd9605d260", + "bladedn": "sys/chassis-1/blade-1" + } + }, + "created": "2013-09-13T22:17:29-0700", + "jobid": "2c3698a8-39ac-43e6-8ade-86eb2d3726a0" + } + }; + */ + //for testing only (end) + + addExtraPropertiesToUcsBladeObject(json.queryasyncjobresultresponse.jobresult.ucsblade); + return json.queryasyncjobresultresponse.jobresult.ucsblade; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } + } + } + } + } + } + } + } + }, + + 'secondary-storage': { + title: 'label.secondary.storage', + id: 'secondarystorages', + sectionSelect: { + label: 'label.select-view' + }, + sections: { + secondaryStorage: { + type: 'select', + title: 'label.secondary.storage', + listView: { + id: 'secondarystorages', + section: 'seconary-storage', + fields: { + name: { + label: 'label.name' + }, + url: { + label: 'label.url' + }, + protocol: { + label: 'label.protocol' + }, + scope: { + label: 'label.scope' + }, + zonename: { + label: 'label.zone' + } + }, + + + dataProvider: function (args) { + var array1 =[]; + if (args.filterBy != null) { + if (args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch (args.filterBy.search.by) { + case "name": + if (args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + array1.push("&zoneid=" + args.context.zones[0].id); + + $.ajax({ + url: createURL("listImageStores&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + dataType: "json", + async: true, + success: function (json) { + var items = json.listimagestoresresponse.imagestore; + args.response.success({ + actionFilter: secondarystorageActionfilter, + data: items + }); + } + }); + }, + + actions: { + add: { + label: 'label.add.secondary.storage', + + createForm: { + title: 'label.add.secondary.storage', + + fields: { + name: { + label: 'label.name' + }, + provider: { + label: 'label.provider', + select: function (args) { + /* + UI no longer gets providers from "listStorageProviders&type=image" because: + (1) Not all of returned values are handled by UI. + (2) Provider "SMB" which is handled by UI is not returned from "listStorageProviders&type=image" + */ + var items =[ { + id: 'NFS', + description: 'NFS' + }, + { + id: 'SMB', + description: 'SMB/CIFS' + }, + { + id: 'S3', + description: 'S3' + }, + { + id: 'Swift', + description: 'Swift' + }]; + + args.response.success({ + data: items + }); + + args.$select.change(function () { + var $form = $(this).closest('form'); + if ($(this).val() == "NFS") { + //NFS, SMB + $form.find('.form-item[rel=zoneid]').css('display', 'inline-block'); + $form.find('.form-item[rel=nfsServer]').css('display', 'inline-block'); + $form.find('.form-item[rel=path]').css('display', 'inline-block'); + + //SMB + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + + //S3 + $form.find('.form-item[rel=accesskey]').hide(); + $form.find('.form-item[rel=secretkey]').hide(); + $form.find('.form-item[rel=bucket]').hide(); + $form.find('.form-item[rel=endpoint]').hide(); + $form.find('.form-item[rel=usehttps]').hide(); + $form.find('.form-item[rel=connectiontimeout]').hide(); + $form.find('.form-item[rel=maxerrorretry]').hide(); + $form.find('.form-item[rel=sockettimeout]').hide(); + + $form.find('.form-item[rel=createNfsCache]').find('input').prop('checked', false); + $form.find('.form-item[rel=createNfsCache]').hide(); + $form.find('.form-item[rel=nfsCacheZoneid]').hide(); + $form.find('.form-item[rel=nfsCacheNfsServer]').hide(); + $form.find('.form-item[rel=nfsCachePath]').hide(); + + //Swift + $form.find('.form-item[rel=url]').hide(); + $form.find('.form-item[rel=account]').hide(); + $form.find('.form-item[rel=username]').hide(); + $form.find('.form-item[rel=key]').hide(); + $form.find('.form-item[rel=storagepolicy]').hide(); + } else if ($(this).val() == "SMB") { + //NFS, SMB + $form.find('.form-item[rel=zoneid]').css('display', 'inline-block'); + $form.find('.form-item[rel=nfsServer]').css('display', 'inline-block'); + $form.find('.form-item[rel=path]').css('display', 'inline-block'); + + //SMB + $form.find('.form-item[rel=smbUsername]').css('display', 'inline-block'); + $form.find('.form-item[rel=smbPassword]').css('display', 'inline-block'); + $form.find('.form-item[rel=smbDomain]').css('display', 'inline-block'); + + //S3 + $form.find('.form-item[rel=accesskey]').hide(); + $form.find('.form-item[rel=secretkey]').hide(); + $form.find('.form-item[rel=bucket]').hide(); + $form.find('.form-item[rel=endpoint]').hide(); + $form.find('.form-item[rel=usehttps]').hide(); + $form.find('.form-item[rel=connectiontimeout]').hide(); + $form.find('.form-item[rel=maxerrorretry]').hide(); + $form.find('.form-item[rel=sockettimeout]').hide(); + + $form.find('.form-item[rel=createNfsCache]').find('input').prop('checked', false); + $form.find('.form-item[rel=createNfsCache]').hide(); + $form.find('.form-item[rel=nfsCacheZoneid]').hide(); + $form.find('.form-item[rel=nfsCacheNfsServer]').hide(); + $form.find('.form-item[rel=nfsCachePath]').hide(); + + //Swift + $form.find('.form-item[rel=url]').hide(); + $form.find('.form-item[rel=account]').hide(); + $form.find('.form-item[rel=username]').hide(); + $form.find('.form-item[rel=key]').hide(); + $form.find('.form-item[rel=storagepolicy]').hide(); + } else if ($(this).val() == "S3") { + //NFS, SMB + $form.find('.form-item[rel=zoneid]').hide(); + $form.find('.form-item[rel=nfsServer]').hide(); + $form.find('.form-item[rel=path]').hide(); + + //SMB + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + + //S3 + $form.find('.form-item[rel=accesskey]').css('display', 'inline-block'); + $form.find('.form-item[rel=secretkey]').css('display', 'inline-block'); + $form.find('.form-item[rel=bucket]').css('display', 'inline-block'); + $form.find('.form-item[rel=endpoint]').css('display', 'inline-block'); + $form.find('.form-item[rel=usehttps]').css('display', 'inline-block'); + $form.find('.form-item[rel=connectiontimeout]').css('display', 'inline-block'); + $form.find('.form-item[rel=maxerrorretry]').css('display', 'inline-block'); + $form.find('.form-item[rel=sockettimeout]').css('display', 'inline-block'); + + $form.find('.form-item[rel=createNfsCache]').find('input').attr('checked', 'checked'); + //$form.find('.form-item[rel=createNfsCache]').find('input').attr('disabled', 'disabled'); //This checkbox should not be disabled any more because NFS staging (of a zone) might already exist (from "NFS secondary storage => Prepare Object Store Migration => NFS staging") + $form.find('.form-item[rel=createNfsCache]').css('display', 'inline-block'); + $form.find('.form-item[rel=nfsCacheZoneid]').css('display', 'inline-block'); + $form.find('.form-item[rel=nfsCacheNfsServer]').css('display', 'inline-block'); + $form.find('.form-item[rel=nfsCachePath]').css('display', 'inline-block'); + + + //Swift + $form.find('.form-item[rel=url]').hide(); + $form.find('.form-item[rel=account]').hide(); + $form.find('.form-item[rel=username]').hide(); + $form.find('.form-item[rel=key]').hide(); + $form.find('.form-item[rel=storagepolicy]').hide(); + } else if ($(this).val() == "Swift") { + //NFS, SMB + $form.find('.form-item[rel=zoneid]').hide(); + $form.find('.form-item[rel=nfsServer]').hide(); + $form.find('.form-item[rel=path]').hide(); + + //SMB + $form.find('.form-item[rel=smbUsername]').hide(); + $form.find('.form-item[rel=smbPassword]').hide(); + $form.find('.form-item[rel=smbDomain]').hide(); + + //S3 + $form.find('.form-item[rel=accesskey]').hide(); + $form.find('.form-item[rel=secretkey]').hide(); + $form.find('.form-item[rel=bucket]').hide(); + $form.find('.form-item[rel=endpoint]').hide(); + $form.find('.form-item[rel=usehttps]').hide(); + $form.find('.form-item[rel=connectiontimeout]').hide(); + $form.find('.form-item[rel=maxerrorretry]').hide(); + $form.find('.form-item[rel=sockettimeout]').hide(); + + $form.find('.form-item[rel=createNfsCache]').find('input').prop('checked', false); + $form.find('.form-item[rel=createNfsCache]').hide(); + $form.find('.form-item[rel=nfsCacheZoneid]').hide(); + $form.find('.form-item[rel=nfsCacheNfsServer]').hide(); + $form.find('.form-item[rel=nfsCachePath]').hide(); + + //Swift + $form.find('.form-item[rel=url]').css('display', 'inline-block'); + $form.find('.form-item[rel=account]').css('display', 'inline-block'); + $form.find('.form-item[rel=username]').css('display', 'inline-block'); + $form.find('.form-item[rel=key]').css('display', 'inline-block'); + $form.find('.form-item[rel=storagepolicy]').css('display', 'inline-block'); + } + }); + + args.$select.change(); + } + }, + + + //NFS, SMB (begin) + zoneid: { + label: 'label.zone', + docID: 'helpSecondaryStorageZone', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL('listZones'), + data: {}, + success: function (json) { + var zones = json.listzonesresponse.zone ? json.listzonesresponse.zone:[]; + + if (zones != null) { + //$.map(items, fn) - items can not be null + args.response.success({ + data: $.map(zones, function (zone) { + return { + id: zone.id, + description: zone.name + }; + }) + }); + } else { + args.response.success({ + data: null + }); + } + } + }); + } + }, + nfsServer: { + label: 'label.server', //change label from "NFS Server" to "Server" since this field is also shown when provider "SMB/CIFS" is elected. + docID: 'helpSecondaryStorageNFSServer', + validation: { + required: true + } + }, + path: { + label: 'label.path', + docID: 'helpSecondaryStoragePath', + validation: { + required: true + } + }, + //NFS, SMB (end) + + + //SMB (begin) + smbUsername: { + label: 'label.smb.username', + validation: { + required: true + } + }, + smbPassword: { + label: 'label.smb.password', + isPassword: true, + validation: { + required: true + } + }, + smbDomain: { + label: 'label.smb.domain', + validation: { + required: true + } + }, + //SMB (end) + + //S3 (begin) + accesskey: { + label: 'label.s3.access_key', + docID: 'helpS3AccessKey', + validation: { + required: true + } + }, + secretkey: { + label: 'label.s3.secret_key', + docID: 'helpS3SecretKey', + validation: { + required: true + } + }, + bucket: { + label: 'label.s3.bucket', + docID: 'helpS3Bucket', + validation: { + required: true + } + }, + endpoint: { + label: 'label.s3.endpoint', + docID: 'helpS3Endpoint' + }, + usehttps: { + label: 'label.s3.use_https', + isEditable: true, + isBoolean: true, + isChecked: true, + converter: cloudStack.converters.toBooleanText + }, + connectiontimeout: { + label: 'label.s3.connection_timeout', + docID: 'helpS3ConnectionTimeout' + }, + maxerrorretry: { + label: 'label.s3.max_error_retry', + docID: 'helpS3MaxErrorRetry' + }, + sockettimeout: { + label: 'label.s3.socket_timeout', + docID: 'helpS3SocketTimeout' + }, + + createNfsCache: { + label: 'label.create.nfs.secondary.staging.store', + isBoolean: true, + isChecked: true + }, + nfsCacheZoneid: { + dependsOn: 'createNfsCache', + label: 'label.zone', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL('listZones'), + data: {}, + success: function (json) { + var zones = json.listzonesresponse.zone; + + if (zones != null) { + //$.map(items, fn) - items can not be null + args.response.success({ + data: $.map(zones, function (zone) { + return { + id: zone.id, + description: zone.name + }; + }) + }); + } else { + args.response.success({ + data: null + }); + } + } + }); + } + }, + nfsCacheNfsServer: { + dependsOn: 'createNfsCache', + label: 'label.nfs.server', + docID: 'helpNFSStagingServer', + validation: { + required: true + } + }, + nfsCachePath: { + dependsOn: 'createNfsCache', + label: 'label.path', + docID: 'helpNFSStagingPath', + validation: { + required: true + } + }, + //S3 (end) + + + //Swift (begin) + url: { + label: 'label.url', + validation: { + required: true + } + }, + account: { + label: 'label.account', + validation: { + required: true + } + }, + username: { + label: 'label.username', + validation: { + required: true + } + }, + key: { + label: 'label.key', + validation: { + required: true + } + }, + storagepolicy: { + label: 'label.storagepolicy' + } + //Swift (end) + } + }, + + action: function (args) { + var data = { + }; + if (args.data.name != null && args.data.name.length > 0) { + $.extend(data, { + name: args.data.name + }); + } + + if (args.data.provider == 'NFS') { + var zoneid = args.data.zoneid; + var nfs_server = args.data.nfsServer; + var path = args.data.path; + var url = nfsURL(nfs_server, path); + + $.extend(data, { + provider: args.data.provider, + zoneid: zoneid, + url: url + }); + + $.ajax({ + url: createURL('addImageStore'), + data: data, + success: function (json) { + var item = json.addimagestoreresponse.imagestore; + args.response.success({ + data: item + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + } else if (args.data.provider == 'SMB') { + var zoneid = args.data.zoneid; + var nfs_server = args.data.nfsServer; + var path = args.data.path; + var url = smbURL(nfs_server, path); + $.extend(data, { + provider: args.data.provider, + zoneid: zoneid, + url: url, + 'details[0].key': 'user', + 'details[0].value': args.data.smbUsername, + 'details[1].key': 'password', + 'details[1].value': args.data.smbPassword, + 'details[2].key': 'domain', + 'details[2].value': args.data.smbDomain + }); + + $.ajax({ + url: createURL('addImageStore'), + data: data, + success: function (json) { + var item = json.addimagestoreresponse.imagestore; + args.response.success({ + data: item + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + } else if (args.data.provider == 'S3') { + $.extend(data, { + provider: args.data.provider, + 'details[0].key': 'accesskey', + 'details[0].value': args.data.accesskey, + 'details[1].key': 'secretkey', + 'details[1].value': args.data.secretkey, + 'details[2].key': 'bucket', + 'details[2].value': args.data.bucket, + 'details[3].key': 'usehttps', + 'details[3].value': (args.data.usehttps != null && args.data.usehttps == 'on' ? 'true': 'false') + }); + + var index = 4; + if (args.data.endpoint != null && args.data.endpoint.length > 0) { + data[ 'details[' + index.toString() + '].key'] = 'endpoint'; + data[ 'details[' + index.toString() + '].value'] = args.data.endpoint; + index++; + } + if (args.data.connectiontimeout != null && args.data.connectiontimeout.length > 0) { + data[ 'details[' + index.toString() + '].key'] = 'connectiontimeout'; + data[ 'details[' + index.toString() + '].value'] = args.data.connectiontimeout; + index++; + } + if (args.data.maxerrorretry != null && args.data.maxerrorretry.length > 0) { + data[ 'details[' + index.toString() + '].key'] = 'maxerrorretry'; + data[ 'details[' + index.toString() + '].value'] = args.data.maxerrorretry; + index++; + } + if (args.data.sockettimeout != null && args.data.sockettimeout.length > 0) { + data[ 'details[' + index.toString() + '].key'] = 'sockettimeout'; + data[ 'details[' + index.toString() + '].value'] = args.data.sockettimeout; + index++; + } + + $.ajax({ + url: createURL('addImageStore'), + data: data, + success: function (json) { + g_regionsecondaryenabled = true; + + var item = json.addimagestoreresponse.imagestore; + args.response.success({ + data: item + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + + if (args.data.createNfsCache == 'on') { + var zoneid = args.data.nfsCacheZoneid; + var nfs_server = args.data.nfsCacheNfsServer; + var path = args.data.nfsCachePath; + var url = nfsURL(nfs_server, path); + + var nfsCacheData = { + provider: 'NFS', + zoneid: zoneid, + url: url + }; + + $.ajax({ + url: createURL('createSecondaryStagingStore'), + data: nfsCacheData, + success: function (json) { + //do nothing + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } else if (args.data.provider == 'Swift') { + $.extend(data, { + provider: args.data.provider, + url: args.data.url + }); + + var index = 0; + if (args.data.account != null && args.data.account.length > 0) { + data[ 'details[' + index.toString() + '].key'] = 'account'; + data[ 'details[' + index.toString() + '].value'] = args.data.account; + index++; + } + if (args.data.username != null && args.data.username.length > 0) { + data[ 'details[' + index.toString() + '].key'] = 'username'; + data[ 'details[' + index.toString() + '].value'] = args.data.username; + index++; + } + if (args.data.key != null && args.data.key.length > 0) { + data[ 'details[' + index.toString() + '].key'] = 'key'; + data[ 'details[' + index.toString() + '].value'] = args.data.key; + index++; + } + if (args.data.storagepolicy != null && args.data.storagepolicy.length > 0) { + data[ 'details[' + index.toString() + '].key'] = 'storagepolicy'; + data[ 'details[' + index.toString() + '].value'] = args.data.storagepolicy; + index++; + } + $.ajax({ + url: createURL('addImageStore'), + data: data, + success: function (json) { + g_regionsecondaryenabled = true; + + var item = json.addimagestoreresponse.imagestore; + args.response.success({ + data: item + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + }, + + notification: { + poll: function (args) { + args.complete({ + actionFilter: secondarystorageActionfilter + }); + } + }, + + messages: { + notification: function (args) { + return 'label.add.secondary.storage'; + } + } + } + }, + + detailView: { + name: 'label.secondary.storage.details', + isMaximized: true, + actions: { + remove: { + label: 'label.action.delete.secondary.storage', + messages: { + confirm: function (args) { + return 'message.action.delete.secondary.storage'; + }, + notification: function (args) { + return 'label.action.delete.secondary.storage'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("deleteImageStore&id=" + args.context.secondaryStorage[0].id), + dataType: "json", + async: true, + success: function (json) { + args.response.success(); + } + }); + }, + notification: { + poll: function (args) { + args.complete({ + data: { + resourcestate: 'Destroyed' + } + }); + } + } + } + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + url: { + label: 'label.url' + }, + protocol: { + label: 'label.protocol' + }, + providername: { + label: 'label.provider' + }, + scope: { + label: 'label.scope' + }, + zonename: { + label: 'label.zone' + }, + id: { + label: 'label.id' + } + }], + + dataProvider: function (args) { + $.ajax({ + url: createURL("listImageStores&id=" + args.context.secondaryStorage[0].id), + dataType: "json", + async: true, + success: function (json) { + var item = json.listimagestoresresponse.imagestore[0]; + processPropertiesInImagestoreObject(item); + args.response.success({ + actionFilter: secondarystorageActionfilter, + data: item + }); + } + }); + } + }, + + // Granular settings for image store + settings: { + title: 'label.settings', + custom: cloudStack.uiCustom.granularSettings({ + dataProvider: function (args) { + + $.ajax({ + url: createURL('listConfigurations&imagestoreuuid=' + args.context.secondaryStorage[0].id), + data: listViewDataProvider(args, { + }, + { + searchBy: 'name' + }), + success: function (json) { + args.response.success({ + data: json.listconfigurationsresponse.configuration + }); + }, + + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + actions: { + edit: function (args) { + // call updateStorageLevelParameters + var data = { + name: args.data.jsonObj.name, + value: args.data.value + }; + + $.ajax({ + url: createURL('updateConfiguration&imagestoreuuid=' + args.context.secondaryStorage[0].id), + data: data, + success: function (json) { + var item = json.updateconfigurationresponse.configuration; + args.response.success({ + data: item + }); + }, + + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + } + }) + } + } + } + } + }, + cacheStorage: { + type: 'select', + title: 'label.secondary.staging.store', + listView: { + id: 'secondarystorages', + section: 'seconary-storage', + fields: { + name: { + label: 'label.name' + }, + url: { + label: 'label.url' + }, + providername: { + label: 'label.provider' + } + }, + + /* + dataProvider: function(args) { //being replaced with dataProvider in line 6898 + var array1 = []; + if(args.filterBy != null) { + if(args.filterBy.search != null && args.filterBy.search.by != null && args.filterBy.search.value != null) { + switch(args.filterBy.search.by) { + case "name": + if(args.filterBy.search.value.length > 0) + array1.push("&keyword=" + args.filterBy.search.value); + break; + } + } + } + array1.push("&zoneid=" + args.context.zones[0].id); + + $.ajax({ + url: createURL("listImageStores&page=" + args.page + "&pagesize=" + pageSize + array1.join("")), + dataType: "json", + async: true, + success: function(json) { + var items = json.listimagestoreresponse.imagestore; + args.response.success({ + actionFilter: secondarystorageActionfilter, + data:items + }); + } + }); + }, + */ + + actions: { + add: { + label: 'label.add.nfs.secondary.staging.store', + createForm: { + title: 'label.add.nfs.secondary.staging.store', + fields: { + zoneid: { + label: 'label.zone', + validation: { + required: true + }, + select: function (args) { + $.ajax({ + url: createURL('listZones'), + data: {}, + success: function (json) { + var zones = json.listzonesresponse.zone ? json.listzonesresponse.zone:[]; + + if (zones != null) { + //$.map(items, fn) - items can not be null + args.response.success({ + data: $.map(zones, function (zone) { + return { + id: zone.id, + description: zone.name + }; + }) + }); + } else { + args.response.success({ + data: null + }); + } + } + }); + } + }, + nfsServer: { + label: 'label.nfs.server', + validation: { + required: true + } + }, + path: { + label: 'label.path', + validation: { + required: true + } + } + } + }, + action: function (args) { + var data = { + provider: 'NFS', + zoneid: args.data.zoneid, + url: nfsURL(args.data.nfsServer, args.data.path) + }; + $.ajax({ + url: createURL('createSecondaryStagingStore'), + data: data, + success: function (json) { + var item = json.createsecondarystagingstoreresponse.secondarystorage; + args.response.success({ + data: item + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + }, + messages: { + notification: function (args) { + return 'label.add.nfs.secondary.staging.store'; + } + } + } + }, + + detailView: { + name: 'label.secondary.staging.store.details', + isMaximized: true, + actions: { + remove: { + label: 'label.delete.secondary.staging.store', + messages: { + confirm: function (args) { + return 'message.confirm.delete.secondary.staging.store'; + }, + notification: function (args) { + return 'label.delete.secondary.staging.store'; + } + }, + action: function (args) { + var data = { + id: args.context.cacheStorage[0].id + }; + $.ajax({ + url: createURL('deleteSecondaryStagingStore'), + data: data, + async: true, + success: function (json) { + args.response.success(); + }, + error: function (data) { + args.response.error(parseXMLHttpResponse(data)); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + } + }, + tabs: { + details: { + title: 'label.details', + fields:[ { + name: { + label: 'label.name' + } + }, + { + url: { + label: 'label.url' + }, + providername: { + label: 'label.provider' + }, + scope: { + label: 'label.scope' + }, + zonename: { + label: 'label.zone' + }, + details: { + label: 'label.details', + converter: function (array1) { + var string1 = ''; + if (array1 != null) { + for (var i = 0; i < array1.length; i++) { + if (i > 0) + string1 += ', '; + + string1 += array1[i].name + ': ' + array1[i].value; + } + } + return string1; + } + }, + id: { + label: 'label.id' + } + }], + + dataProvider: function (args) { + $.ajax({ + url: createURL('listSecondaryStagingStores'), + data: { + id: args.context.cacheStorage[0].id + }, + async: false, + success: function (json) { + var item = json.listsecondarystagingstoreresponse.imagestore[0]; + args.response.success({ + data: item + }); + } + }); + } + } + + // Granular settings for storage pool for secondary storage is not required + /* settings: { + title: 'label.menu.global.settings', + custom: cloudStack.uiCustom.granularSettings({ + dataProvider: function(args) { + args.response.success({ + data: [ + { name: 'config.param.1', value: 1 }, + { name: 'config.param.2', value: 2 } + ] + }); + }, + actions: { + edit: function(args) { + // call updateStorageLevelParameters + args.response.success(); + } + } + }) + } */ + } + } + } + } + } + }, + + guestIpRanges: { + //Advanced zone - Guest traffic type - Network tab - Network detailView - View IP Ranges + title: 'label.guest.ip.range', + id: 'guestIpRanges', + listView: { + section: 'guest-IP-range', + fields: { + startip: { + label: 'label.ipv4.start.ip' + }, + endip: { + label: 'label.ipv4.end.ip' + }, + startipv6: { + label: 'label.ipv6.start.ip' + }, + endipv6: { + label: 'label.ipv6.end.ip' + }, + gateway: { + label: 'label.gateway' + }, + netmask: { + label: 'label.netmask' + } + }, + + dataProvider: function (args) { + $.ajax({ + url: createURL("listVlanIpRanges&zoneid=" + selectedZoneObj.id + "&networkid=" + args.context.networks[0].id + "&page=" + args.page + "&pagesize=" + pageSize), + dataType: "json", + async: true, + success: function (json) { + var items = json.listvlaniprangesresponse.vlaniprange; + args.response.success({ + data: items + }); + } + }); + }, + + actions: { + add: { + label: 'label.add.ip.range', + createForm: { + title: 'label.add.ip.range', + fields: { + gateway: { + label: 'label.gateway' + }, + netmask: { + label: 'label.netmask' + }, + startipv4: { + label: 'label.ipv4.start.ip' + }, + endipv4: { + label: 'label.ipv4.end.ip' + }, + ip6cidr: { + label: 'label.ipv6.CIDR' + }, + ip6gateway: { + label: 'label.ipv6.gateway' + }, + startipv6: { + label: 'label.ipv6.start.ip' + }, + endipv6: { + label: 'label.ipv6.end.ip' + } + } + }, + action: function (args) { + var array2 =[]; + + if (args.data.gateway != null && args.data.gateway.length > 0) + array2.push("&gateway=" + args.data.gateway); + if (args.data.netmask != null && args.data.netmask.length > 0) + array2.push("&netmask=" + args.data.netmask); + + if (args.data.startipv4 != null && args.data.startipv4.length > 0) + array2.push("&startip=" + args.data.startipv4); + if (args.data.endipv4 != null && args.data.endipv4.length > 0) + array2.push("&endip=" + args.data.endipv4); + + if (args.data.ip6cidr != null && args.data.ip6cidr.length > 0) + array2.push("&ip6cidr=" + args.data.ip6cidr); + if (args.data.ip6gateway != null && args.data.ip6gateway.length > 0) + array2.push("&ip6gateway=" + args.data.ip6gateway); + + if (args.data.startipv6 != null && args.data.startipv6.length > 0) + array2.push("&startipv6=" + args.data.startipv6); + if (args.data.endipv6 != null && args.data.endipv6.length > 0) + array2.push("&endipv6=" + args.data.endipv6); + + $.ajax({ + url: createURL("createVlanIpRange&forVirtualNetwork=false&networkid=" + args.context.networks[0].id + array2.join("")), + dataType: "json", + success: function (json) { + var item = json.createvlaniprangeresponse.vlan; + args.response.success({ + data: item + }); + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + args.response.error(errorMsg); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + }, + messages: { + notification: function (args) { + return 'label.add.ip.range'; + } + } + }, + + 'remove': { + label: 'label.remove.ip.range', + messages: { + confirm: function (args) { + return 'message.confirm.remove.IP.range'; + }, + notification: function (args) { + return 'label.remove.ip.range'; + } + }, + action: function (args) { + $.ajax({ + url: createURL("deleteVlanIpRange&id=" + args.data.id), + dataType: "json", + async: true, + success: function (json) { + args.response.success({ + data: { + } + }); + }, + error: function (json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + }, + notification: { + poll: function (args) { + args.complete(); + } + } + } + } + } + } + } + }; + + function addBaremetalDhcpDeviceFn(args) { + if (nspMap[ "BaremetalDhcpProvider"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=BaremetalDhcpProvider&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addBaremetalDhcpProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addBaremetalDhcpProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "BaremetalDhcpProvider"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + + $.ajax({ + url: createURL('addBaremetalDhcp'), + data: { + physicalnetworkid: selectedPhysicalNetworkObj.id, + dhcpservertype: 'DHCPD', + url: args.data.url, + username: args.data.username, + password: args.data.password + }, + type: "POST", + success: function (json) { + var jid = json.addbaremetaldhcpresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + var item = json.queryasyncjobresultresponse.jobresult.baremetaldhcp; + return item; + } + } + }); + } + }); + } else if (result.jobstatus == 2) { + alert(_s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + alert(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else { + $.ajax({ + url: createURL('addBaremetalDhcp'), + data: { + physicalnetworkid: selectedPhysicalNetworkObj.id, + dhcpservertype: 'DHCPD', + url: args.data.url, + username: args.data.username, + password: args.data.password + }, + type: "POST", + success: function (json) { + var jid = json.addbaremetaldhcpresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + var item = json.queryasyncjobresultresponse.jobresult.baremetaldhcp; + return item; + } + } + }); + } + }); + } + } + + function addBaremetalPxeDeviceFn(args) { + if (nspMap[ "BaremetalPxeProvider"] == null) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=BaremetalPxeProvider&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addBaremetalPxeProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addBaremetalPxeProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "BaremetalPxeProvider"] = json.queryasyncjobresultresponse.jobresult.networkserviceprovider; + + $.ajax({ + url: createURL('addBaremetalPxeKickStartServer'), + data: { + physicalnetworkid: selectedPhysicalNetworkObj.id, + pxeservertype: 'KICK_START', + url: args.data.url, + username: args.data.username, + password: args.data.password, + tftpdir: args.data.tftpdir + }, + type: "POST", + success: function (json) { + var jid = json.addbaremetalpxeresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + var item = json.queryasyncjobresultresponse.jobresult.baremetalpxeserver; + return item; + } + } + }); + } + }); + } else if (result.jobstatus == 2) { + alert(_s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + alert(parseXMLHttpResponse(XMLHttpResponse)); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else { + $.ajax({ + url: createURL('addBaremetalPxeKickStartServer'), + data: { + physicalnetworkid: selectedPhysicalNetworkObj.id, + pxeservertype: 'KICK_START', + url: args.data.url, + username: args.data.username, + password: args.data.password, + tftpdir: args.data.tftpdir + }, + type: "POST", + success: function (json) { + var jid = json.addbaremetalpxeresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + var item = json.queryasyncjobresultresponse.jobresult.baremetalpxeserver; + return item; + } + } + }); + } + }); + } + } + + // Inject cloudStack infra page + cloudStack.sections.system.show = cloudStack.uiCustom.physicalResources(cloudStack.sections.system.physicalResourceSection); + + function addExternalLoadBalancer(args, physicalNetworkObj, apiCmd, apiCmdRes, apiCmdObj) { + var array1 =[]; + array1.push("&physicalnetworkid=" + physicalNetworkObj.id); + cloudStack.addUsernameAndPasswordToCommandUrlParameterArrayIfItIsNotNullAndNotEmpty(array1, args.data.username, args.data.password); + array1.push("&networkdevicetype=" + encodeURIComponent(args.data.networkdevicetype)); + + if (apiCmd == "addNetscalerLoadBalancer") { + array1.push("&gslbprovider=" + (args.data.gslbprovider == "on")); + array1.push("&gslbproviderpublicip=" + encodeURIComponent(args.data.gslbproviderpublicip)); + array1.push("&gslbproviderprivateip=" + encodeURIComponent(args.data.gslbproviderprivateip)); + } + + //construct URL starts here + var url =[]; + + var ip = args.data.ip; + url.push("https://" + ip); + + var isQuestionMarkAdded = false; + + var publicInterface = args.data.publicinterface; + if (publicInterface != null && publicInterface.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("publicinterface=" + publicInterface); + } + + var privateInterface = args.data.privateinterface; + if (privateInterface != null && privateInterface.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("privateinterface=" + privateInterface); + } + + var numretries = args.data.numretries; + if (numretries != null && numretries.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("numretries=" + numretries); + } + + var isInline = args.data.inline; + if (isInline != null && isInline.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("inline=" + isInline); + } + + var capacity = args.data.capacity; + if (capacity != null && capacity.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("lbdevicecapacity=" + capacity); + } + + var dedicated = (args.data.dedicated == "on"); + //boolean (true/false) + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("lbdevicededicated=" + dedicated.toString()); + + + array1.push("&url=" + encodeURIComponent(url.join(""))); + //construct URL ends here + + $.ajax({ + url: createURL(apiCmd + array1.join("")), + dataType: "json", + type: "POST", + success: function (json) { + var jid = json[apiCmdRes].jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + var item = json.queryasyncjobresultresponse.jobresult[apiCmdObj]; + + return item; + } + } + }); + } + }); + } + + function addExternalFirewall(args, physicalNetworkObj, apiCmd, apiCmdRes, apiCmdObj) { + var array1 =[]; + array1.push("&physicalnetworkid=" + physicalNetworkObj.id); + cloudStack.addUsernameAndPasswordToCommandUrlParameterArrayIfItIsNotNullAndNotEmpty(array1, args.data.username, args.data.password); + array1.push("&networkdevicetype=" + encodeURIComponent(args.data.networkdevicetype)); + + //construct URL starts here + var url =[]; + + var ip = args.data.ip; + url.push("https://" + ip); + + var isQuestionMarkAdded = false; + + var publicInterface = args.data.publicinterface; + if (publicInterface != null && publicInterface.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("publicinterface=" + publicInterface); + } + + var privateInterface = args.data.privateinterface; + if (privateInterface != null && privateInterface.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("privateinterface=" + privateInterface); + } + + var usageInterface = args.data.usageinterface; + if (usageInterface != null && usageInterface.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("usageinterface=" + usageInterface); + } + + var numretries = args.data.numretries; + if (numretries != null && numretries.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("numretries=" + numretries); + } + + var timeout = args.data.timeout; + if (timeout != null && timeout.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("timeout=" + timeout); + } + + var isInline = args.data.inline; + if (isInline != null && isInline.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("inline=" + isInline); + } + + var publicNetwork = args.data.publicnetwork; + if (publicNetwork != null && publicNetwork.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("publicnetwork=" + publicNetwork); + } + + var privateNetwork = args.data.privatenetwork; + if (privateNetwork != null && privateNetwork.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("privatenetwork=" + privateNetwork); + } + + var capacity = args.data.capacity; + if (capacity != null && capacity.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("fwdevicecapacity=" + capacity); + } + + var dedicated = (args.data.dedicated == "on"); + //boolean (true/false) + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("fwdevicededicated=" + dedicated.toString()); + + // START - Palo Alto Specific Fields + var externalVirtualRouter = args.data.pavr; + if (externalVirtualRouter != null && externalVirtualRouter.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("pavr=" + encodeURIComponent(externalVirtualRouter)); + } + + var externalThreatProfile = args.data.patp; + if (externalThreatProfile != null && externalThreatProfile.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("patp=" + encodeURIComponent(externalThreatProfile)); + } + + var externalLogProfile = args.data.palp; + if (externalLogProfile != null && externalLogProfile.length > 0) { + if (isQuestionMarkAdded == false) { + url.push("?"); + isQuestionMarkAdded = true; + } else { + url.push("&"); + } + url.push("palp=" + encodeURIComponent(externalLogProfile)); + } + // END - Palo Alto Specific Fields + + array1.push("&url=" + encodeURIComponent(url.join(""))); + //construct URL ends here + + $.ajax({ + url: createURL(apiCmd + array1.join("")), + dataType: "json", + type: "POST", + success: function (json) { + var jid = json[apiCmdRes].jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + var item = json.queryasyncjobresultresponse.jobresult[apiCmdObj]; + + return item; + } + } + }); + } + }); + } + + function addNiciraNvpDevice(args, physicalNetworkObj, apiCmd, apiCmdRes, apiCmdObj) { + var array1 =[]; + array1.push("&physicalnetworkid=" + physicalNetworkObj.id); + cloudStack.addUsernameAndPasswordToCommandUrlParameterArrayIfItIsNotNullAndNotEmpty(array1, rgs.data.username, args.data.password); + array1.push("&hostname=" + encodeURIComponent(args.data.host)); + array1.push("&transportzoneuuid=" + encodeURIComponent(args.data.transportzoneuuid)); + + var l3GatewayServiceUuid = args.data.l3gatewayserviceuuid; + if (l3GatewayServiceUuid != null && l3GatewayServiceUuid.length > 0) { + array1.push("&l3gatewayserviceuuid=" + encodeURIComponent(args.data.l3gatewayserviceuuid)); + } + + var l2GatewayServiceUuid = args.data.l2gatewayserviceuuid; + if (l2GatewayServiceUuid != null && l2GatewayServiceUuid.length > 0) { + array1.push("&l2gatewayserviceuuid=" + encodeURIComponent(args.data.l2gatewayserviceuuid)); + } + + $.ajax({ + url: createURL(apiCmd + array1.join("")), + dataType: "json", + type: "POST", + success: function (json) { + var jid = json[apiCmdRes].jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + var item = json.queryasyncjobresultresponse.jobresult[apiCmdObj]; + + return item; + } + } + }); + } + }); + } + + function addBrocadeVcsDevice(args, physicalNetworkObj, apiCmd, apiCmdRes, apiCmdObj) { + var array1 =[]; + array1.push("&physicalnetworkid=" + physicalNetworkObj.id); + cloudStack.addUsernameAndPasswordToCommandUrlParameterArrayIfItIsNotNullAndNotEmpty(array1, args.data.username, args.data.password); + array1.push("&hostname=" + encodeURIComponent(args.data.host)); + + $.ajax({ + url: createURL(apiCmd + array1.join("")), + dataType: "json", + type: "POST", + success: function (json) { + var jid = json[apiCmdRes].jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + var item = json.queryasyncjobresultresponse.jobresult[apiCmdObj]; + + return item; + } + } + }); + } + }); + } + + function addOpenDaylightController(args, physicalNetworkObj, apiCmd, apiCmdRes, apiCmdObj) { + var array1 =[]; + array1.push("&physicalnetworkid=" + physicalNetworkObj.id); + cloudStack.addUsernameAndPasswordToCommandUrlParameterArrayIfItIsNotNullAndNotEmpty(array1, args.data.username, args.data.password); + array1.push("&url=" + encodeURIComponent(args.data.url)); + + $.ajax({ + url: createURL(apiCmd + array1.join("")), + dataType: "json", + type: "POST", + success: function (json) { + var jid = json[apiCmdRes].jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + var item = json.queryasyncjobresultresponse.jobresult[apiCmdObj]; + + return item; + } + } + }); + } + }); + } + + function addBigSwitchBcfDevice(args, physicalNetworkObj, apiCmd, apiCmdRes, apiCmdObj) { + var array1 =[]; + array1.push("&physicalnetworkid=" + physicalNetworkObj.id); + array1.push("&hostname=" + encodeURIComponent(args.data.host)); + array1.push("&username=" + encodeURIComponent(args.data.username)); + cloudStack.addPasswordToCommandUrlParameterArray(array1, args.data.password); + array1.push("&nat=" + (args.data.nat == 'on' ? "true": "false")); + + $.ajax({ + url: createURL(apiCmd + array1.join("")), + dataType: "json", + success: function (json) { + var jid = json[apiCmdRes].jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + var item = json.queryasyncjobresultresponse.jobresult[apiCmdObj]; + + return item; + } + } + }); + } + }); + } + + function addGloboDnsHost(args, physicalNetworkObj, apiCmd, apiCmdRes) { + var array1 = []; + array1.push("&physicalnetworkid=" + physicalNetworkObj.id); + cloudStack.addUsernameAndPasswordToCommandUrlParameterArrayIfItIsNotNullAndNotEmpty(array1, args.data.username, args.data.password); + array1.push("&url=" + encodeURIComponent(args.data.url)); + + $.ajax({ + url: createURL(apiCmd + array1.join("")), + dataType: "json", + type: "POST", + success: function(json) { + var jid = json[apiCmdRes].jobid; + args.response.success({ + _custom: { + jobId: jid + } + }); + } + }); + } + + + var afterCreateZonePhysicalNetworkTrafficTypes = function (args, newZoneObj, newPhysicalnetwork) { + $.ajax({ + url: createURL("updatePhysicalNetwork&state=Enabled&id=" + newPhysicalnetwork.id), + dataType: "json", + success: function (json) { + var jobId = json.updatephysicalnetworkresponse.jobid; + var enablePhysicalNetworkIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(enablePhysicalNetworkIntervalID); + if (result.jobstatus == 1) { + //alert("updatePhysicalNetwork succeeded."); + + // get network service provider ID of Virtual Router + var virtualRouterProviderId; + $.ajax({ + url: createURL("listNetworkServiceProviders&name=VirtualRouter&physicalNetworkId=" + newPhysicalnetwork.id), + dataType: "json", + async: false, + success: function (json) { + var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; + if (items != null && items.length > 0) { + virtualRouterProviderId = items[0].id; + } + } + }); + if (virtualRouterProviderId == null) { + alert("error: listNetworkServiceProviders API doesn't return VirtualRouter provider ID"); + return; + } + + var virtualRouterElementId; + $.ajax({ + url: createURL("listVirtualRouterElements&nspid=" + virtualRouterProviderId), + dataType: "json", + async: false, + success: function (json) { + var items = json.listvirtualrouterelementsresponse.virtualrouterelement; + if (items != null && items.length > 0) { + virtualRouterElementId = items[0].id; + } + } + }); + if (virtualRouterElementId == null) { + alert("error: listVirtualRouterElements API doesn't return Virtual Router Element Id"); + return; + } + + $.ajax({ + url: createURL("configureVirtualRouterElement&enabled=true&id=" + virtualRouterElementId), + dataType: "json", + async: false, + success: function (json) { + var jobId = json.configurevirtualrouterelementresponse.jobid; + var enableVirtualRouterElementIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(enableVirtualRouterElementIntervalID); + if (result.jobstatus == 1) { + //alert("configureVirtualRouterElement succeeded."); + + $.ajax({ + url: createURL("updateNetworkServiceProvider&state=Enabled&id=" + virtualRouterProviderId), + dataType: "json", + async: false, + success: function (json) { + var jobId = json.updatenetworkserviceproviderresponse.jobid; + var enableVirtualRouterProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(enableVirtualRouterProviderIntervalID); + if (result.jobstatus == 1) { + //alert("Virtual Router Provider is enabled"); + + if (newZoneObj.networktype == "Basic") { + if (args.data[ "security-groups-enabled"] == "on") { + //need to Enable security group provider first + // get network service provider ID of Security Group + var securityGroupProviderId; + $.ajax({ + url: createURL("listNetworkServiceProviders&name=SecurityGroupProvider&physicalNetworkId=" + newPhysicalnetwork.id), + dataType: "json", + async: false, + success: function (json) { + var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; + if (items != null && items.length > 0) { + securityGroupProviderId = items[0].id; + } + } + }); + if (securityGroupProviderId == null) { + alert("error: listNetworkServiceProviders API doesn't return security group provider ID"); + return; + } + + $.ajax({ + url: createURL("updateNetworkServiceProvider&state=Enabled&id=" + securityGroupProviderId), + dataType: "json", + async: false, + success: function (json) { + var jobId = json.updatenetworkserviceproviderresponse.jobid; + var enableSecurityGroupProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(enableSecurityGroupProviderIntervalID); + if (result.jobstatus == 1) { + //alert("Security group provider is enabled"); + + //create network (for basic zone only) + var array2 =[]; + array2.push("&zoneid=" + newZoneObj.id); + array2.push("&name=guestNetworkForBasicZone"); + array2.push("&displaytext=guestNetworkForBasicZone"); + array2.push("&networkofferingid=" + args.data.networkOfferingId); + $.ajax({ + url: createURL("createNetwork" + array2.join("")), + dataType: "json", + async: false, + success: function (json) { + var arrayOfParameters = cloudStack.createArrayOfParametersForCreatePodCommand(newZoneObj.id, args.data); + $.ajax({ + url: createURL("createPod" + arrayOfParameters.join("")), + dataType: "json", + async: false, + success: function (json) { + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("createPod failed. Error: " + errorMsg); + } + }); + } + }); + } else if (result.jobstatus == 2) { + alert("failed to enable security group provider. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("updateNetworkServiceProvider failed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else { + //create network (for basic zone only) + var array2 =[]; + array2.push("&zoneid=" + newZoneObj.id); + array2.push("&name=guestNetworkForBasicZone"); + array2.push("&displaytext=guestNetworkForBasicZone"); + array2.push("&networkofferingid=" + args.data.networkOfferingId); + $.ajax({ + url: createURL("createNetwork" + array2.join("")), + dataType: "json", + async: false, + success: function (json) { + var arrayOfParameters = cloudStack.createArrayOfParametersForCreatePodCommand(newZoneObj.id, args.data); + $.ajax({ + url: createURL("createPod" + arrayOfParameters.join("")), + dataType: "json", + async: false, + success: function (json) { + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("createPod failed. Error: " + errorMsg); + } + }); + } + }); + } + } else { + var arrayOfParameters = cloudStack.createArrayOfParametersForCreatePodCommand(newZoneObj.id, args.data); + $.ajax({ + url: createURL("createPod" + arrayOfParameters.join("")), + dataType: "json", + async: false, + success: function (json) { + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("createPod failed. Error: " + errorMsg); + } + }); + } + } else if (result.jobstatus == 2) { + alert("failed to enable Virtual Router Provider. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("updateNetworkServiceProvider failed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else if (result.jobstatus == 2) { + alert("configureVirtualRouterElement failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("configureVirtualRouterElement failed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + } else if (result.jobstatus == 2) { + alert("updatePhysicalNetwork failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("updatePhysicalNetwork failed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + }; + + //action filters (begin) + var zoneActionfilter = cloudStack.actionFilter.zoneActionfilter = function (args) { + var jsonObj = args.context.item; + var allowedActions =[ 'enableSwift']; + + if (jsonObj.vmwaredcId == null) { + allowedActions.push('addVmwareDc'); + } else { + allowedActions.push('updateVmwareDc'); + allowedActions.push('removeVmwareDc'); + } + + if (jsonObj.domainid != null) + allowedActions.push("releaseDedicatedZone"); else + allowedActions.push("dedicateZone"); + + allowedActions.push("edit"); + + if (jsonObj.allocationstate == "Disabled") + allowedActions.push("enable"); else if (jsonObj.allocationstate == "Enabled") + allowedActions.push("disable"); + + allowedActions.push("remove"); + + if (jsonObj.hasOwnProperty('resourcedetails') && jsonObj['resourcedetails'].hasOwnProperty('outOfBandManagementEnabled') && jsonObj['resourcedetails']['outOfBandManagementEnabled'] == 'false') { + allowedActions.push("enableOutOfBandManagement"); + } else { + allowedActions.push("disableOutOfBandManagement"); + } + + if (jsonObj.hasOwnProperty('resourcedetails') && jsonObj['resourcedetails'].hasOwnProperty('resourceHAEnabled') && jsonObj['resourcedetails']['resourceHAEnabled'] == 'false') { + allowedActions.push("enableHA"); + } else { + allowedActions.push("disableHA"); + } + + allowedActions.push("startRollingMaintenance"); + return allowedActions; + } + + + var nexusActionfilter = function (args) { + var nexusObj = args.context.item; + var allowedActions =[]; + allowedActions.push("edit"); + if (nexusObj.vsmdevicestate == "Disabled") + allowedActions.push("enable"); else if (nexusObj.vsmdevicestate == "Enabled") + allowedActions.push("disable"); + allowedActions.push("remove"); + return allowedActions; + } + + var podActionfilter = function (args) { + var podObj = args.context.item; + var dedicatedPodObj = args.context.podItem; + var allowedActions =[]; + + if (podObj.domainid != null) + allowedActions.push("release"); else + allowedActions.push("dedicate"); + + + allowedActions.push("edit"); + if (podObj.allocationstate == "Disabled") + allowedActions.push("enable"); else if (podObj.allocationstate == "Enabled") + allowedActions.push("disable"); + allowedActions.push("remove"); + + /* + var selectedZoneObj; + $(zoneObjs).each(function(){ + if(this.id == podObj.zoneid) { + selectedZoneObj = this; + return false; //break the $.each() loop + } + }); + */ + + if (selectedZoneObj.networktype == "Basic") { + //basic-mode network (pod-wide VLAN) + //$("#tab_ipallocation, #add_iprange_button, #tab_network_device, #add_network_device_button").show(); + allowedActions.push("addIpRange"); + allowedActions.push("addNetworkDevice"); + } else if (selectedZoneObj.networktype == "Advanced") { + //advanced-mode network (zone-wide VLAN) + //$("#tab_ipallocation, #add_iprange_button, #tab_network_device, #add_network_device_button").hide(); + } + + allowedActions.push("startRollingMaintenance"); + return allowedActions; + } + + var networkDeviceActionfilter = function (args) { + var jsonObj = args.context.item; + var allowedActions =[]; + return allowedActions; + } + + var clusterActionfilter = function (args) { + var jsonObj = args.context.item; + var allowedActions =[]; + + if (jsonObj.domainid != null) + allowedActions.push("release"); else + allowedActions.push("dedicate"); + + if (jsonObj.state == "Enabled") { + //managed, allocation enabled + allowedActions.push("unmanage"); + allowedActions.push("disable"); + //allowedActions.push("edit"); // No fields to edit + } else if (jsonObj.state == "Disabled") { + //managed, allocation disabled + allowedActions.push("unmanage"); + allowedActions.push("enable"); + //allowedActions.push("edit"); // No fields to edit + } else { + //Unmanaged, PrepareUnmanaged , PrepareUnmanagedError + allowedActions.push("manage"); + } + + allowedActions.push("remove"); + + if (jsonObj.hasOwnProperty('resourcedetails') && jsonObj['resourcedetails'].hasOwnProperty('outOfBandManagementEnabled') && jsonObj['resourcedetails']['outOfBandManagementEnabled'] == 'false') { + allowedActions.push("enableOutOfBandManagement"); + } else { + allowedActions.push("disableOutOfBandManagement"); + } + + if (jsonObj.hasOwnProperty('resourcedetails') && jsonObj['resourcedetails'].hasOwnProperty('resourceHAEnabled') && jsonObj['resourcedetails']['resourceHAEnabled'] == 'false') { + allowedActions.push("enableHA"); + } else { + allowedActions.push("disableHA"); + } + + allowedActions.push("startRollingMaintenance"); + return allowedActions; + } + + var hostActionfilter = function (args) { + var jsonObj = args.context.item; + var allowedActions =[]; + + if (jsonObj.domainid != null) + allowedActions.push("release"); else + allowedActions.push("dedicate"); + + + if (jsonObj.resourcestate == "Enabled") { + allowedActions.push("edit"); + allowedActions.push("enableMaintenanceMode"); + allowedActions.push("disable"); + + if (jsonObj.state != "Disconnected") + allowedActions.push("forceReconnect"); + + if (jsonObj.hypervisor == "KVM") { + allowedActions.push("secureKVMHost"); + allowedActions.push("startRollingMaintenance"); + } + + } else if (jsonObj.resourcestate == "ErrorInMaintenance") { + allowedActions.push("edit"); + allowedActions.push("enableMaintenanceMode"); + allowedActions.push("cancelMaintenanceMode"); + if (jsonObj.hypervisor == "KVM") { + allowedActions.push("startRollingMaintenance"); + } + } else if (jsonObj.resourcestate == "PrepareForMaintenance" || jsonObj.resourcestate == 'ErrorInPrepareForMaintenance') { + allowedActions.push("edit"); + allowedActions.push("cancelMaintenanceMode"); + } else if (jsonObj.resourcestate == "Maintenance") { + allowedActions.push("edit"); + allowedActions.push("cancelMaintenanceMode"); + allowedActions.push("remove"); + } else if (jsonObj.resourcestate == "Disabled") { + allowedActions.push("edit"); + allowedActions.push("enable"); + allowedActions.push("remove"); + } + + allowedActions.push("blankHAForHost"); + allowedActions.push("configureHAForHost"); + if (jsonObj.hasOwnProperty("hostha") && jsonObj.hostha.haenable) { + allowedActions.push("disableHA"); + } else { + allowedActions.push("enableHA"); + } + + allowedActions.push("blankOutOfBandManagement"); + allowedActions.push("configureOutOfBandManagement"); + if (jsonObj.hasOwnProperty("outofbandmanagement") && jsonObj.outofbandmanagement.enabled) { + allowedActions.push("issueOutOfBandManagementPowerAction"); + allowedActions.push("changeOutOfBandManagementPassword"); + allowedActions.push("disableOutOfBandManagement"); + } else { + allowedActions.push("enableOutOfBandManagement"); + } + + if ((jsonObj.state == "Down" || jsonObj.state == "Alert" || jsonObj.state == "Disconnected") && ($.inArray("remove", allowedActions) == -1)) { + allowedActions.push("remove"); + } + + return allowedActions; + } + + var primarystorageActionfilter = function (args) { + var jsonObj = args.context.item; + var allowedActions =[]; + + allowedActions.push("edit"); + + if (jsonObj.state == 'Up' || jsonObj.state == "Connecting") { + allowedActions.push("enableMaintenanceMode"); + } else if (jsonObj.state == 'Down') { + allowedActions.push("enableMaintenanceMode"); + allowedActions.push("remove"); + } else if (jsonObj.state == "Alert") { + allowedActions.push("remove"); + } else if (jsonObj.state == "ErrorInMaintenance") { + allowedActions.push("enableMaintenanceMode"); + allowedActions.push("cancelMaintenanceMode"); + } else if (jsonObj.state == "PrepareForMaintenance" || jsonObj.resourcestate == "ErrorInPrepareForMaintenance") { + allowedActions.push("cancelMaintenanceMode"); + } else if (jsonObj.state == "Maintenance") { + allowedActions.push("cancelMaintenanceMode"); + allowedActions.push("remove"); + } else if (jsonObj.state == "Disconnected") { + allowedActions.push("remove"); + } + return allowedActions; + } + + var secondarystorageActionfilter = function (args) { + var jsonObj = args.context.item; + var allowedActions = []; + allowedActions.push("remove"); + return allowedActions; + } + + var routerActionfilter = cloudStack.sections.system.routerActionFilter = function (args) { + var jsonObj = args.context.item; + var allowedActions =[]; + + if (jsonObj.requiresupgrade == true) { + allowedActions.push('upgradeRouterToUseNewerTemplate'); + } + + if (jsonObj.state == 'Running') { + allowedActions.push("stop"); + + //when router is Running, only VMware support scaleUp(change service offering) + if (jsonObj.hypervisor == "VMware") { + allowedActions.push("scaleUp"); + } + + allowedActions.push("restart"); + allowedActions.push("remove"); + allowedActions.push("viewConsole"); + + if (isAdmin()) { + allowedActions.push("migrate"); + allowedActions.push("diagnostics"); + allowedActions.push("retrieveDiagnostics"); + allowedActions.push("healthChecks"); + } + } else if (jsonObj.state == 'Stopped') { + allowedActions.push("start"); + + //when router is Stopped, all hypervisors support scaleUp(change service offering) + allowedActions.push("scaleUp"); + + allowedActions.push("remove"); + } + if (jsonObj.state == 'Starting' || jsonObj.state == 'Stopping' || jsonObj.state == 'Migrating') { + allowedActions.push("viewConsole"); + } + return allowedActions; + } + + var internallbinstanceActionfilter = function (args) { + var jsonObj = args.context.item; + var allowedActions =[]; + + if (jsonObj.state == 'Running') { + allowedActions.push("stop"); + allowedActions.push("viewConsole"); + if (isAdmin()) + allowedActions.push("migrate"); + } else if (jsonObj.state == 'Stopped') { + allowedActions.push("start"); + } + if (jsonObj.state == 'Starting' || jsonObj.state == 'Stopping' || jsonObj.state == 'Migrating') { + allowedActions.push("viewConsole"); + } + return allowedActions; + } + + var systemvmActionfilter = function (args) { + var jsonObj = args.context.item; + var allowedActions =[]; + + if (jsonObj.state == 'Running') { + allowedActions.push("stop"); + allowedActions.push("restart"); + allowedActions.push("remove"); + + //when systemvm is Running, only VMware support scaleUp(change service offering) + if (jsonObj.hypervisor == "VMware") { + allowedActions.push("scaleUp"); + } + + allowedActions.push("viewConsole"); + if (isAdmin()) { + allowedActions.push("migrate"); + allowedActions.push("diagnostics"); + allowedActions.push("retrieveDiagnostics"); + } + } else if (jsonObj.state == 'Stopped') { + allowedActions.push("start"); + + //when systemvm is Stopped, all hypervisors support scaleUp(change service offering) + allowedActions.push("scaleUp"); + + allowedActions.push("remove"); + } else if (jsonObj.state == 'Error') { + allowedActions.push("remove"); + } + if (jsonObj.state == 'Starting' || jsonObj.state == 'Stopping' || jsonObj.state == 'Migrating') { + allowedActions.push("viewConsole"); + } + return allowedActions; + } + + var routerGroupActionfilter = function (args) { + var jsonObj = args.context.item; + var allowedActions =[]; + if (jsonObj.routerRequiresUpgrade > 0) { + allowedActions.push("upgradeRouterToUseNewerTemplate"); + } + return allowedActions; + } + + var bladeActionfilter = function (args) { + var jsonObj = args.context.item; + var allowedActions =[]; + if (jsonObj.profiledn == null) { + allowedActions.push("associateTemplateToBlade"); + } else { + allowedActions.push("disassociateProfileFromBlade"); + } + return allowedActions; + } + + //action filters (end) + + var networkProviderActionFilter = function (id) { + return function (args) { + var allowedActions =[]; + var jsonObj = nspMap[id] ? + nspMap[id]: { + }; + + if (id == "netscaler") { + var netscalerControlCenter = null; + + $.ajax({ + url: createURL("listNetscalerControlCenter"), + dataType: "json", + async: false, + success: function(json) { + var items = json.listNetscalerControlCenter.netscalercontrolcenter; + if (items != null && items.length > 0) { + netscalerControlCenter = items[0]; + } + } + }); + } + + if (netscalerControlCenter != null) { + if (jsonObj.state == undefined) { + $.ajax({ + url: createURL("addNetworkServiceProvider&name=Netscaler&physicalnetworkid=" + selectedPhysicalNetworkObj.id), + dataType: "json", + async: true, + success: function (json) { + var jobId = json.addnetworkserviceproviderresponse.jobid; + var addNetscalerProviderIntervalID = setInterval(function () { + $.ajax({ + url: createURL("queryAsyncJobResult&jobId=" + jobId), + dataType: "json", + success: function (json) { + var result = json.queryasyncjobresultresponse; + if (result.jobstatus == 0) { + return; //Job has not completed + } else { + clearInterval(addNetscalerProviderIntervalID); + if (result.jobstatus == 1) { + nspMap[ "netscaler"] = result.jobresult.networkserviceprovider; + addExternalLoadBalancer(args, selectedPhysicalNetworkObj, "addNetscalerLoadBalancer", "addnetscalerloadbalancerresponse", "netscalerloadbalancer"); + } else if (result.jobstatus == 2) { + alert("addNetworkServiceProvider&name=Netscaler failed. Error: " + _s(result.jobresult.errortext)); + } + } + }, + error: function (XMLHttpResponse) { + var errorMsg = parseXMLHttpResponse(XMLHttpResponse); + alert("addNetworkServiceProvider&name=Netscaler failed. Error: " + errorMsg); + } + }); + }, + g_queryAsyncJobResultInterval); + } + }); + jsonObj.state = "Disabled"; + } + } + + if (jsonObj.state) { + if (jsonObj.state == "Enabled") + allowedActions.push("disable"); else if (jsonObj.state == "Disabled") + allowedActions.push("enable"); + allowedActions.push("destroy"); + } + + allowedActions.push('add'); + + return allowedActions; + } + }; + + var addExtraPropertiesToClusterObject = function (jsonObj) { + if (jsonObj.managedstate == "Managed") { + jsonObj.state = jsonObj.allocationstate; //jsonObj.state == Enabled, Disabled + } else { + jsonObj.state = jsonObj.managedstate; //jsonObj.state == Unmanaged, PrepareUnmanaged, PrepareUnmanagedError + } + } + + var addExtraPropertiesToRouterInstanceObject = function (jsonObj) { + if (jsonObj.isredundantrouter == true) { + jsonObj[ "redundantRouterState"] = jsonObj.redundantstate; + } else { + jsonObj[ "redundantRouterState"] = ""; + } + } + + var refreshNspData = function (nspName) { + var array1 =[]; + if (nspName != null) + array1.push("&name=" + nspName); + + $.ajax({ + url: createURL("listNetworkServiceProviders&physicalnetworkid=" + selectedPhysicalNetworkObj.id + array1.join("")), + dataType: "json", + async: false, + success: function (json) { + nspMap = { + }; + //reset + + var items = json.listnetworkserviceprovidersresponse.networkserviceprovider; + if (items != null) { + for (var i = 0; i < items.length; i++) { + switch (items[i].name) { + case "VirtualRouter": + nspMap[ "virtualRouter"] = items[i]; + break; + case "InternalLbVm": + nspMap[ "InternalLbVm"] = items[i]; + break; + case "VpcVirtualRouter": + nspMap[ "vpcVirtualRouter"] = items[i]; + break; + case "Ovs": + nspMap["Ovs"] = items[i]; + break; + case "Netscaler": + nspMap[ "netscaler"] = items[i]; + break; + case "BaremetalDhcpProvider": + nspMap[ "BaremetalDhcpProvider"] = items[i]; + break; + case "BaremetalPxeProvider": + nspMap[ "BaremetalPxeProvider"] = items[i]; + break; + case "F5BigIp": + nspMap[ "f5"] = items[i]; + break; + case "JuniperSRX": + nspMap[ "srx"] = items[i]; + break; + case "PaloAlto": + nspMap[ "pa"] = items[i]; + break; + case "SecurityGroupProvider": + nspMap[ "securityGroups"] = items[i]; + break; + case "NiciraNvp": + nspMap[ "niciraNvp"] = items[i]; + break; + case "BrocadeVcs": + nspMap[ "brocadeVcs"] = items[i]; + break; + case "BigSwitchBcf": + nspMap[ "bigswitchBcf"] = items[i]; + break; + case "Ovs": + nspMap[ "Ovs"] = items[i]; + break; + case "Opendaylight": + nspMap[ "Opendaylight"] = items[i]; + break; + case "GloboDns": + nspMap["GloboDns"] = items[i]; + break; + case "ConfigDrive": + nspMap["ConfigDrive"] = items[i]; + break; + case "Tungsten": + nspMap["Tungsten"] = items[i]; + break; + } + } + } + } + }); + + nspHardcodingArray =[ { + id: 'netscaler', + name: 'NetScaler', + state: nspMap.netscaler ? nspMap.netscaler.state: 'Disabled' + }, + { + id: 'virtualRouter', + name: 'Virtual Router', + state: nspMap.virtualRouter ? nspMap.virtualRouter.state: 'Disabled' + }, + { + id: 'Tungsten', + name: 'Tungsten', + state: nspMap.Tungsten ? nspMap.Tungsten.state : 'Disabled' + }, + { + id: 'niciraNvp', + name: 'Nicira Nvp', + state: nspMap.niciraNvp ? nspMap.niciraNvp.state: 'Disabled' + }, + { + id: 'brocadeVcs', + name: 'Brocade', + state: nspMap.brocadeVcs ? nspMap.brocadeVcs.state: 'Disabled' + }, + { + id: 'bigswitchBcf', + name: 'BigSwitch BCF', + state: nspMap.bigswitchBcf ? nspMap.bigswitchBcf.state: 'Disabled' + }, + { + id: 'BaremetalDhcpProvider', + name: 'Baremetal DHCP', + state: nspMap.BaremetalDhcpProvider ? nspMap.BaremetalDhcpProvider.state: 'Disabled' + }, + { + id: 'BaremetalPxeProvider', + name: 'Baremetal PXE', + state: nspMap.BaremetalPxeProvider ? nspMap.BaremetalPxeProvider.state: 'Disabled' + }, + { + id: 'Opendaylight', + name: 'OpenDaylight (Experimental)', + state: nspMap.Opendaylight ? nspMap.Opendaylight.state: 'Disabled' + }]; + + $(window).trigger('cloudStack.system.serviceProviders.makeHarcodedArray', { + nspHardcodingArray: nspHardcodingArray, + selectedZoneObj: selectedZoneObj, + selectedPhysicalNetworkObj: selectedPhysicalNetworkObj + }); + + if (selectedZoneObj.networktype == "Basic") { + nspHardcodingArray.push({ + id: 'securityGroups', + name: 'Security Groups', + state: nspMap.securityGroups ? nspMap.securityGroups.state: 'Disabled' + }); + } else if (selectedZoneObj.networktype == "Advanced") { + nspHardcodingArray.push({ + id: 'InternalLbVm', + name: 'Internal LB VM', + state: nspMap.InternalLbVm ? nspMap.InternalLbVm.state: 'Disabled' + }); + + nspHardcodingArray.push({ + id: 'vpcVirtualRouter', + name: 'VPC Virtual Router', + state: nspMap.vpcVirtualRouter ? nspMap.vpcVirtualRouter.state: 'Disabled' + }); + nspHardcodingArray.push({ + id: 'f5', + name: 'F5', + state: nspMap.f5 ? nspMap.f5.state: 'Disabled' + }); + nspHardcodingArray.push({ + id: 'srx', + name: 'SRX', + state: nspMap.srx ? nspMap.srx.state: 'Disabled' + }); + nspHardcodingArray.push({ + id: 'pa', + name: 'Palo Alto', + state: nspMap.pa ? nspMap.pa.state: 'Disabled' + }); + nspHardcodingArray.push({ + id: 'GloboDns', + name: 'GloboDNS', + state: nspMap.GloboDns ? nspMap.GloboDns.state : 'Disabled' + }); + nspHardcodingArray.push({ + id: "ConfigDrive", + name: "ConfigDrive", + state: nspMap.ConfigDrive ? nspMap.ConfigDrive.state : 'Disabled' + }); + + //CLOUDSTACK-6840: OVS refers to SDN provider. However, we are not supporting SDN in this release. + /* + nspHardcodingArray.push({ + id: 'Ovs', + name: 'Ovs', + state: nspMap.Ovs ? nspMap.Ovs.state: 'Disabled' + }); + */ + } + }; + + cloudStack.actionFilter.physicalNetwork = function (args) { + var state = args.context.item.state; + + if (state != 'Destroyed') { + return[ 'remove']; + } + + return[]; + }; + + function addExtraPropertiesToGroupbyObjects(groupbyObjs, groupbyId) { + for (var i = 0; i < groupbyObjs.length; i++) { + addExtraPropertiesToGroupbyObject(groupbyObjs[i], groupbyId); + } + } + + function addExtraPropertiesToGroupbyObject(groupbyObj, groupbyId) { + var currentPage = 1; + + var listRoutersData = { + listAll: true, + pagesize: pageSize //global variable + }; + listRoutersData[groupbyId] = groupbyObj.id; + + $.ajax({ + url: createURL('listRouters'), + data: $.extend({ + }, + listRoutersData, { + page: currentPage + }), + async: false, + success: function(json) { + if (json.listroutersresponse.count != undefined) { + var routerCountFromAllPages = json.listroutersresponse.count; + var routerCountFromFirstPageToCurrentPage = json.listroutersresponse.router.length; + var routerRequiresUpgrade = 0; + + var items = json.listroutersresponse.router; + for (var k = 0; k < items.length; k++) { + if (items[k].requiresupgrade) { + routerRequiresUpgrade++; + } + } + + $.ajax({ + url: createURL('listRouters'), + data: $.extend({}, listRoutersData, { + page: currentPage, + projectid: -1 + }), + async: false, + success: function(json) { + if (json.listroutersresponse.count != undefined) { + routerCountFromAllPages += json.listroutersresponse.count; + groupbyObj.routerCount = routerCountFromAllPages; + + routerCountFromFirstPageToCurrentPage += json.listroutersresponse.router.length; + + var items = json.listroutersresponse.router; + for (var k = 0; k < items.length; k++) { + if (items[k].requiresupgrade) { + routerRequiresUpgrade++; + } + } + } else { + groupbyObj.routerCount = routerCountFromAllPages; + } + } + }); + + var callListApiWithPage = function() { + $.ajax({ + url: createURL('listRouters'), + async: false, + data: $.extend({}, listRoutersData, { + page: currentPage + }), + success: function(json) { + routerCountFromFirstPageToCurrentPage += json.listroutersresponse.router.length; + var items = json.listroutersresponse.router; + for (var k = 0; k < items.length; k++) { + if (items[k].requiresupgrade) { + routerRequiresUpgrade++; + } + } + + $.ajax({ + url: createURL('listRouters'), + async: false, + data: $.extend({}, listRoutersData, { + page: currentPage, + projectid: -1 + }), + success: function(json) { + if (json.listroutersresponse.count != undefined) { + routerCountFromAllPages += json.listroutersresponse.count; + groupbyObj.routerCount = routerCountFromAllPages; + + routerCountFromFirstPageToCurrentPage += json.listroutersresponse.router.length; + + var items = json.listroutersresponse.router; + for (var k = 0; k < items.length; k++) { + if (items[k].requiresupgrade) { + routerRequiresUpgrade++; + } + } + } else { + groupbyObj.routerCount = routerCountFromAllPages; + } + } + }); + + if (routerCountFromFirstPageToCurrentPage < routerCountFromAllPages) { + currentPage++; + callListApiWithPage(); + } + } + }); + } + + if (routerCountFromFirstPageToCurrentPage < routerCountFromAllPages) { + currentPage++; + callListApiWithPage(); + } + + groupbyObj.routerRequiresUpgrade = routerRequiresUpgrade; + groupbyObj.numberOfRouterRequiresUpgrade = routerRequiresUpgrade; + } else { + groupbyObj.routerCount = 0; + groupbyObj.routerRequiresUpgrade = 0; + groupbyObj.numberOfRouterRequiresUpgrade = 0; + } + } + }); + } +})($, cloudStack); From 12ff070250626a69aa5b578563e3cee2ed5a36ad Mon Sep 17 00:00:00 2001 From: rtodirica Date: Thu, 3 Sep 2020 21:04:22 +0300 Subject: [PATCH 07/62] Added tungsten provider Added create project/domain in tungsten that match project/domain from cloudstack Did some code refactoring --- .../main/java/com/cloud/event/EventTypes.java | 2 + .../main/java/com/cloud/network/Network.java | 4 - .../com/cloud/network/TungstenProvider.java | 7 + .../network/guru/NetworkGuruTungsten.java | 4 +- .../orchestration/NetworkOrchestrator.java | 14 +- .../java/com/cloud/network/dao/NetworkVO.java | 32 -- .../PhysicalNetworkServiceProviderDao.java | 6 +- ...PhysicalNetworkServiceProviderDaoImpl.java | 15 +- .../network/dao/TungstenProviderDao.java | 12 + .../network/dao/TungstenProviderDaoImpl.java | 53 +++ .../network/element/TungstenProviderVO.java | 98 +++++ ...spring-engine-schema-core-daos-context.xml | 1 + .../META-INF/db/schema-41400to41500.sql | 16 +- .../command/CreateTungstenProviderCmd.java | 130 ++++++ .../command/DeleteTungstenProviderCmd.java | 63 +++ .../api/command/ListTungstenProvidersCmd.java | 77 ++++ .../response/TungstenProviderResponse.java | 60 +++ .../tungsten/service/TungstenElement.java | 2 - .../service/TungstenGuestNetworkGuru.java | 31 +- .../tungsten/service/TungstenManager.java | 30 +- .../tungsten/service/TungstenManagerImpl.java | 376 +++++++++--------- .../service/TungstenProviderService.java | 22 + .../service/TungstenProviderServiceImpl.java | 105 +++++ .../service/TungstenResponseHelper.java | 34 +- .../tungsten/service/TungstenService.java | 13 +- .../tungsten/service/TungstenServiceImpl.java | 285 ++++++++++--- .../tungsten/spring-tungsten-context.xml | 3 + tools/apidoc/gen_toc.py | 4 + ui/l10n/en.js | 8 + ui/scripts/system.js | 249 +++++++++++- 30 files changed, 1402 insertions(+), 354 deletions(-) create mode 100644 api/src/main/java/com/cloud/network/TungstenProvider.java create mode 100644 engine/schema/src/main/java/com/cloud/network/dao/TungstenProviderDao.java create mode 100644 engine/schema/src/main/java/com/cloud/network/dao/TungstenProviderDaoImpl.java create mode 100644 engine/schema/src/main/java/com/cloud/network/element/TungstenProviderVO.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenProviderCmd.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenProviderCmd.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenProvidersCmd.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenProviderResponse.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderService.java create mode 100644 plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderServiceImpl.java diff --git a/api/src/main/java/com/cloud/event/EventTypes.java b/api/src/main/java/com/cloud/event/EventTypes.java index f351ab575661..e9d0210ebd74 100644 --- a/api/src/main/java/com/cloud/event/EventTypes.java +++ b/api/src/main/java/com/cloud/event/EventTypes.java @@ -168,6 +168,8 @@ public class EventTypes { public static final String EVENT_TUNGSTEN_INSTANCE_IP = "TUNGSTEN.INSTANCE.IP"; public static final String EVENT_TUNGSTEN_ADD_VROUTER_PORT = "TUNGSTEN.VROUTER.PORT.ADD"; public static final String EVENT_TUNGSTEN_DEL_VROUTER_PORT = "TUNGSTEN.VROUTER.PORT.DEL"; + public static final String EVENT_TUNGSTEN_ADD_PROVIDER = "TUNGSTEN.ADD.PROVIDER"; + public static final String EVENT_TUNGSTEN_DELETE_PROVIDER = "TUNGSTEN.DELETE.PROVIDER"; //NIC Events public static final String EVENT_NIC_CREATE = "NIC.CREATE"; diff --git a/api/src/main/java/com/cloud/network/Network.java b/api/src/main/java/com/cloud/network/Network.java index 31df22bf1895..ed63afe504f6 100644 --- a/api/src/main/java/com/cloud/network/Network.java +++ b/api/src/main/java/com/cloud/network/Network.java @@ -407,10 +407,6 @@ public void setIp6Address(String ip6Address) { TrafficType getTrafficType(); - String getTungstenNetworkUuid(); - - void setTungstenNetworkUuid(String tungstenNetworkUuid); - String getGateway(); // "cidr" is the Cloudstack managed address space, all CloudStack managed vms get IP address from "cidr", diff --git a/api/src/main/java/com/cloud/network/TungstenProvider.java b/api/src/main/java/com/cloud/network/TungstenProvider.java new file mode 100644 index 000000000000..323e75cce963 --- /dev/null +++ b/api/src/main/java/com/cloud/network/TungstenProvider.java @@ -0,0 +1,7 @@ +package com.cloud.network; + +import org.apache.cloudstack.api.Identity; +import org.apache.cloudstack.api.InternalIdentity; + +public interface TungstenProvider extends InternalIdentity, Identity { +} diff --git a/api/src/main/java/com/cloud/network/guru/NetworkGuruTungsten.java b/api/src/main/java/com/cloud/network/guru/NetworkGuruTungsten.java index 41fdc3313fd0..d678308e0484 100644 --- a/api/src/main/java/com/cloud/network/guru/NetworkGuruTungsten.java +++ b/api/src/main/java/com/cloud/network/guru/NetworkGuruTungsten.java @@ -1,11 +1,13 @@ package com.cloud.network.guru; import com.cloud.network.Network; +import com.cloud.user.Account; +import java.io.IOException; import java.util.List; public interface NetworkGuruTungsten { - Network createNetworkInTungsten(Network networkVO); + void createNetworkInTungsten(Network networkVO, Account owner) throws IOException; String createVirtualMachineInTungsten(String virtualMachineUuid, String virtualMachineName); String createVmInterfaceInTungsten(String vmInterfaceName, String tungstenProjectUuid, String tungstenNetworkUuid, String tungstenVirtualMachineUuid, String tungstenSecurityGroupUuid, List tungstenVmInterfaceMacAddresses); void createTungstenInstanceIp(String instanceIpName, String tungstenVmInterfaceUuid, String tungstenNetworkUuid, String tungstenInstanceIpAddress); diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index ca21d53b16c3..c77d89c29726 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -211,6 +211,7 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; +import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; @@ -708,7 +709,11 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { vo.setStrechedL2Network(offering.isSupportingStrechedL2()); if(guru instanceof NetworkGuruTungsten){ - vo = (NetworkVO) ((NetworkGuruTungsten) guru).createNetworkInTungsten(vo); + try { + ((NetworkGuruTungsten) guru).createNetworkInTungsten(vo, owner); + } catch (IOException e) { + throw new CloudRuntimeException("Unable to create a network in tungsten"); + } } final NetworkVO networkPersisted = _networksDao.persist(vo, vo.getGuestType() == Network.GuestType.Isolated, @@ -1763,13 +1768,6 @@ public NicProfile prepareNic(final VirtualMachineProfile vmProfile, final Deploy profile.setSecurityGroupEnabled(_networkModel.isSecurityGroupSupportedInNetwork(network)); guru.updateNicProfile(profile, network); - if(guru instanceof NetworkGuruTungsten){ - String tungstenVirtualMachineUuid = ((NetworkGuruTungsten) guru).createVirtualMachineInTungsten(vmProfile.getUuid(), vmProfile.getInstanceName()); - String tungstenVmInterfaceUuid = ((NetworkGuruTungsten) guru).createVmInterfaceInTungsten(vmProfile.getInstanceName(), "2853b16f-176e-4c7d-8931-423e496fad38", - network.getTungstenNetworkUuid(), tungstenVirtualMachineUuid, null, Arrays.asList(nic.getMacAddress())); - ((NetworkGuruTungsten) guru).createTungstenInstanceIp("TungstenInstanceTest", tungstenVmInterfaceUuid, network.getTungstenNetworkUuid(), nic.getIPv4Address()); - } - configureExtraDhcpOptions(network, nicId); return profile; } diff --git a/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java b/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java index e25c83293bdb..5833f6d86e2a 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/NetworkVO.java @@ -85,9 +85,6 @@ public class NetworkVO implements Network { @Column(name = "vpc_id") Long vpcId; - @Column(name = "tungsten_network_uuid") - String tungstenNetworkUuid; - @Column(name = "physical_network_id") Long physicalNetworkId; @@ -288,26 +285,6 @@ public NetworkVO(long id, TrafficType trafficType, Mode mode, BroadcastDomainTyp this.vpcId = vpcId; } - public NetworkVO(long id, TrafficType trafficType, Mode mode, BroadcastDomainType broadcastDomainType, long networkOfferingId, long domainId, long accountId, - long related, String name, String displayText, String networkDomain, GuestType guestType, long dcId, Long physicalNetworkId, ACLType aclType, - boolean specifyIpRanges, Long vpcId, final boolean isRedundant, String tungstenNetworkUuid) { - this(trafficType, mode, broadcastDomainType, networkOfferingId, State.Allocated, dcId, physicalNetworkId, isRedundant); - this.domainId = domainId; - this.accountId = accountId; - this.related = related; - this.id = id; - this.name = name; - this.displayText = displayText; - this.aclType = aclType; - this.networkDomain = networkDomain; - uuid = UUID.randomUUID().toString(); - this.guestType = guestType; - this.specifyIpRanges = specifyIpRanges; - this.vpcId = vpcId; - this.tungstenNetworkUuid = tungstenNetworkUuid; - - } - @Override public String getReservationId() { return reservationId; @@ -418,15 +395,6 @@ public TrafficType getTrafficType() { return trafficType; } - @Override - public String getTungstenNetworkUuid() { - return tungstenNetworkUuid; - } - - public void setTungstenNetworkUuid(String tungstenNetworkUuid) { - this.tungstenNetworkUuid = tungstenNetworkUuid; - } - @Override public void setTrafficType(TrafficType trafficType) { this.trafficType = trafficType; diff --git a/engine/schema/src/main/java/com/cloud/network/dao/PhysicalNetworkServiceProviderDao.java b/engine/schema/src/main/java/com/cloud/network/dao/PhysicalNetworkServiceProviderDao.java index 0121b2e03902..283a333336b7 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/PhysicalNetworkServiceProviderDao.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/PhysicalNetworkServiceProviderDao.java @@ -16,15 +16,17 @@ // under the License. package com.cloud.network.dao; -import java.util.List; - import com.cloud.utils.db.GenericDao; +import java.util.List; + public interface PhysicalNetworkServiceProviderDao extends GenericDao { List listBy(long physicalNetworkId); PhysicalNetworkServiceProviderVO findByServiceProvider(long physicalNetworkId, String providerType); + PhysicalNetworkServiceProviderVO findByProviderName(String providerType); + void deleteProviders(long physicalNetworkId); boolean isServiceProviderEnabled(long physicalNetworkId, String providerType, String serviceType); diff --git a/engine/schema/src/main/java/com/cloud/network/dao/PhysicalNetworkServiceProviderDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/PhysicalNetworkServiceProviderDaoImpl.java index 75c70d14e3a5..9db67155e3e3 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/PhysicalNetworkServiceProviderDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/PhysicalNetworkServiceProviderDaoImpl.java @@ -16,11 +16,6 @@ // under the License. package com.cloud.network.dao; -import java.util.List; - - -import org.springframework.stereotype.Component; - import com.cloud.network.Network.Service; import com.cloud.network.PhysicalNetworkServiceProvider; import com.cloud.utils.db.DB; @@ -28,6 +23,9 @@ import com.cloud.utils.db.SearchBuilder; import com.cloud.utils.db.SearchCriteria; import com.cloud.utils.db.SearchCriteria.Op; +import org.springframework.stereotype.Component; + +import java.util.List; @Component @DB() @@ -80,6 +78,13 @@ public PhysicalNetworkServiceProviderVO findByServiceProvider(long physicalNetwo return findOneBy(sc); } + @Override + public PhysicalNetworkServiceProviderVO findByProviderName(String providerType) { + SearchCriteria sc = physicalNetworkServiceProviderSearch.create(); + sc.setParameters("serviceProvderType", providerType); + return findOneBy(sc); + } + @Override public void deleteProviders(long physicalNetworkId) { SearchCriteria sc = physicalNetworkSearch.create(); diff --git a/engine/schema/src/main/java/com/cloud/network/dao/TungstenProviderDao.java b/engine/schema/src/main/java/com/cloud/network/dao/TungstenProviderDao.java new file mode 100644 index 000000000000..02f14a5a7d45 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/dao/TungstenProviderDao.java @@ -0,0 +1,12 @@ +package com.cloud.network.dao; + +import com.cloud.network.element.TungstenProviderVO; +import com.cloud.utils.db.GenericDao; + +public interface TungstenProviderDao extends GenericDao { + TungstenProviderVO findByNspId(long nspId); + + TungstenProviderVO findByUuid(String uuid); + + void deleteProviderByUuid(String providerUuid); +} diff --git a/engine/schema/src/main/java/com/cloud/network/dao/TungstenProviderDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/TungstenProviderDaoImpl.java new file mode 100644 index 000000000000..57612e900acc --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/dao/TungstenProviderDaoImpl.java @@ -0,0 +1,53 @@ +package com.cloud.network.dao; + +import com.cloud.network.element.TungstenProviderVO; +import com.cloud.utils.db.DB; +import com.cloud.utils.db.GenericDaoBase; +import com.cloud.utils.db.SearchBuilder; +import com.cloud.utils.db.SearchCriteria; +import org.springframework.stereotype.Component; + +@Component +@DB() +public class TungstenProviderDaoImpl extends GenericDaoBase + implements TungstenProviderDao { + + final SearchBuilder AllFieldsSearch; + + public TungstenProviderDaoImpl() { + super(); + AllFieldsSearch = createSearchBuilder(); + AllFieldsSearch.and("id", AllFieldsSearch.entity().getId(), + SearchCriteria.Op.EQ); + AllFieldsSearch.and("uuid", AllFieldsSearch.entity().getUuid(), + SearchCriteria.Op.EQ); + AllFieldsSearch.and("hostname", AllFieldsSearch.entity().getHostname(), + SearchCriteria.Op.EQ); + AllFieldsSearch.and("provider_name", AllFieldsSearch.entity().getProviderName(), + SearchCriteria.Op.EQ); + AllFieldsSearch.and("port", AllFieldsSearch.entity().getPort(), + SearchCriteria.Op.EQ); + AllFieldsSearch.done(); + } + + @Override + public TungstenProviderVO findByNspId(long nspId) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("nsp_id", nspId); + return findOneBy(sc); + } + + @Override + public TungstenProviderVO findByUuid(String uuid) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("uuid", uuid); + return findOneBy(sc); + } + + @Override + public void deleteProviderByUuid(String providerUuid) { + SearchCriteria sc = AllFieldsSearch.create(); + sc.setParameters("uuid", providerUuid); + remove(sc); + } +} diff --git a/engine/schema/src/main/java/com/cloud/network/element/TungstenProviderVO.java b/engine/schema/src/main/java/com/cloud/network/element/TungstenProviderVO.java new file mode 100644 index 000000000000..a93b83659418 --- /dev/null +++ b/engine/schema/src/main/java/com/cloud/network/element/TungstenProviderVO.java @@ -0,0 +1,98 @@ +package com.cloud.network.element; + +import com.cloud.network.TungstenProvider; + +import javax.persistence.Column; +import javax.persistence.Entity; +import javax.persistence.GeneratedValue; +import javax.persistence.GenerationType; +import javax.persistence.Id; +import javax.persistence.Table; +import java.util.UUID; + +@Entity +@Table(name = ("tungsten_providers")) +public class TungstenProviderVO implements TungstenProvider { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + long id; + + @Column(name = "nsp_id") + private long nspId; + + @Column(name = "uuid") + private String uuid; + + @Column(name = "provider_name") + private String providerName; + + @Column(name = "port") + private String port; + + @Column(name = "hostname") + private String hostname; + + public TungstenProviderVO() { + this.uuid = UUID.randomUUID().toString(); + } + + public TungstenProviderVO(long nspId, String providerName, String port, String hostname) { + this.nspId = nspId; + this.uuid = UUID.randomUUID().toString(); + this.providerName = providerName; + this.port = port; + this.hostname = hostname; + } + + @Override + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + @Override + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public String getProviderName() { + return providerName; + } + + public void setProviderName(String providerName) { + this.providerName = providerName; + } + + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } + + public long getNspId() { + return nspId; + } + + public void setNspId(long nspId) { + this.nspId = nspId; + } +} diff --git a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml index b670621de9f0..68c2d705eb80 100644 --- a/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml +++ b/engine/schema/src/main/resources/META-INF/cloudstack/core/spring-engine-schema-core-daos-context.xml @@ -152,6 +152,7 @@ + diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql b/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql index ca0226724df6..5603ee4029db 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql @@ -82,4 +82,18 @@ CREATE VIEW `cloud`.`network_offering_view` AS LEFT JOIN `cloud`.`data_center` AS `zone` ON FIND_IN_SET(`zone`.`id`, `zone_details`.`value`) GROUP BY - `network_offerings`.`id`; \ No newline at end of file + `network_offerings`.`id`; + + +DROP TABLE IF EXISTS `cloud`.`tungsten_providers`; +CREATE TABLE `cloud`.`tungsten_providers` ( + `id` bigint unsigned NOT NULL auto_increment COMMENT 'id', + `nsp_id` bigint unsigned NOT NULL COMMENT 'Network Service Provider ID', + `uuid` varchar(40), + `provider_name` varchar(40), + `port` varchar(40), + `hostname` varchar(40), + PRIMARY KEY (`id`), + CONSTRAINT `fk_tungsten_providers__nsp_id` FOREIGN KEY (`nsp_id`) REFERENCES `physical_network_service_providers` (`id`) ON DELETE CASCADE, + CONSTRAINT `uc_tungsten_providers__uuid` UNIQUE (`uuid`) +) ENGINE=InnoDB DEFAULT CHARSET=utf8; \ No newline at end of file diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenProviderCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenProviderCmd.java new file mode 100644 index 000000000000..5e4151ea851b --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenProviderCmd.java @@ -0,0 +1,130 @@ +package org.apache.cloudstack.network.tungsten.api.command; + +import com.cloud.event.EventTypes; +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.TungstenProvider; +import com.cloud.network.element.TungstenProviderVO; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseAsyncCreateCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.DomainResponse; +import org.apache.cloudstack.api.response.ProjectResponse; +import org.apache.cloudstack.api.response.ProviderResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.network.tungsten.api.response.TungstenProviderResponse; +import org.apache.cloudstack.network.tungsten.service.TungstenProviderService; +import org.apache.cloudstack.network.tungsten.service.TungstenResponseHelper; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; + +@APICommand(name = "createTungstenProvider", + description = "Create tungsten provider in cloudstack", + responseObject = TungstenProviderResponse.class) +public class CreateTungstenProviderCmd extends BaseAsyncCreateCmd { + + private static final String s_name = "createtungstenproviderresponse"; + + //Owner information + @Parameter(name = ApiConstants.ACCOUNT, type = CommandType.STRING, description = "An optional account for the virtual machine. Must be used with domainId.") + private String accountName; + + @Parameter(name = ApiConstants.DOMAIN_ID, + type = CommandType.UUID, + entityType = DomainResponse.class, + description = "An optional domainId for the virtual machine. If the account parameter is used, domainId must also be used.") + private Long domainId; + + @Parameter(name = ApiConstants.PROJECT_ID, type = CommandType.UUID, entityType = ProjectResponse.class, description = "Project ID for the service instance") + private Long projectId; + + @Parameter(name = ApiConstants.NSP_ID, type = CommandType.UUID, entityType = ProviderResponse.class, description = "network service provider id") + private Long nspId; + + @Parameter(name = ApiConstants.NAME, type = CommandType.STRING, required = true, description = "Tungsten provider name") + private String name; + + @Parameter(name = ApiConstants.TUNGSTEN_PROVIDER_HOSTNAME, type = CommandType.STRING, required = true, description = "Tungsten provider hostname") + private String hostname; + + @Parameter(name = ApiConstants.TUNGSTEN_PROVIDER_PORT, type = CommandType.STRING, required = true, description = "Tungsten provider port") + private String port; + + public Long getNspId() { + return nspId; + } + + public String getName() { + return name; + } + + public String getHostname() { + return hostname; + } + + public String getPort() { + return port; + } + + @Inject + private TungstenProviderService tungstenProviderService; + + @Override + public void create() throws ResourceAllocationException { + try { + TungstenProvider tungstenProvider = tungstenProviderService.addProvider(this); + if (tungstenProvider != null) { + setEntityId(tungstenProvider.getId()); + setEntityUuid(tungstenProvider.getUuid()); + } else { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create tungsten provider"); + } + } catch (ConfigurationException e) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create tungsten provider"); + } + } + + @Override + public String getEventType() { + return EventTypes.EVENT_TUNGSTEN_ADD_PROVIDER; + } + + @Override + public String getEventDescription() { + return "Create tungsten provider in cloudstack"; + } + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + TungstenProviderVO tungstenProviderVO = tungstenProviderService.getTungstenProvider(); + if (tungstenProviderVO == null) + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to create tungsten provider"); + else { + TungstenProviderResponse response = TungstenResponseHelper.createTungstenProviderResponse(tungstenProviderVO); + response.setResponseName(getCommandName()); + setResponseObject(response); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + Long accountId = _accountService.finalyzeAccountId(accountName, domainId, projectId, true); + if (accountId == null) { + return CallContext.current().getCallingAccount().getId(); + } + + return accountId; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenProviderCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenProviderCmd.java new file mode 100644 index 000000000000..60547a2f5262 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/DeleteTungstenProviderCmd.java @@ -0,0 +1,63 @@ +package org.apache.cloudstack.network.tungsten.api.command; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.TungstenProvider; +import com.cloud.user.Account; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.SuccessResponse; +import org.apache.cloudstack.network.tungsten.service.TungstenProviderService; + +import javax.inject.Inject; + +@APICommand(name = "deleteTungstenProvider", + description = "Delete tungsten provider", + responseObject = SuccessResponse.class, + entityType = {TungstenProvider.class}, + requestHasSensitiveInfo = false, + responseHasSensitiveInfo = false) +public class DeleteTungstenProviderCmd extends BaseCmd { + + private static final String s_name = "deletetungstenproviderresponse"; + + @Parameter(name = ApiConstants.TUNGSTEN_PROVIDER_UUID, type = CommandType.STRING, required = true, description = "The UUID of the tungsten provider") + private String tungstenProviderUuid; + + public String getTungstenProviderUuid() { + return tungstenProviderUuid; + } + + @Inject + private TungstenProviderService tungstenProviderService; + + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, NetworkRuleConflictException { + try { + tungstenProviderService.deleteTungstenProvider(this); + SuccessResponse response = new SuccessResponse(getCommandName()); + setResponseObject(response); + } catch (InvalidParameterValueException e) { + throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete tungsten provider"); + } + } + + @Override + public String getCommandName() { + return s_name; + } + + @Override + public long getEntityOwnerId() { + return Account.ACCOUNT_ID_SYSTEM; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenProvidersCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenProvidersCmd.java new file mode 100644 index 000000000000..31f03ac90016 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/ListTungstenProvidersCmd.java @@ -0,0 +1,77 @@ +package org.apache.cloudstack.network.tungsten.api.command; + +import com.cloud.exception.ConcurrentOperationException; +import com.cloud.exception.InsufficientCapacityException; +import com.cloud.exception.NetworkRuleConflictException; +import com.cloud.exception.ResourceAllocationException; +import com.cloud.exception.ResourceUnavailableException; +import com.cloud.network.element.TungstenProviderVO; +import org.apache.cloudstack.api.APICommand; +import org.apache.cloudstack.api.ApiConstants; +import org.apache.cloudstack.api.BaseCmd; +import org.apache.cloudstack.api.Parameter; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.api.response.ListResponse; +import org.apache.cloudstack.context.CallContext; +import org.apache.cloudstack.network.tungsten.api.response.TungstenProviderResponse; +import org.apache.cloudstack.network.tungsten.service.TungstenProviderService; +import org.apache.cloudstack.network.tungsten.service.TungstenResponseHelper; + +import javax.inject.Inject; +import java.util.ArrayList; +import java.util.List; + +@APICommand(name = "listTungstenProviders", responseObject = TungstenProviderResponse.class, description = "Lists Tungsten providers", + requestHasSensitiveInfo = false, responseHasSensitiveInfo = false) +public class ListTungstenProvidersCmd extends BaseCmd { + + ///////////////////////////////////////////////////// + //////////////// API parameters ///////////////////// + ///////////////////////////////////////////////////// + + @Parameter(name = ApiConstants.TUNGSTEN_PROVIDER_UUID, type = CommandType.UUID, entityType = TungstenProviderResponse.class, required = false, + description = "the ID of a tungsten provider") + private Long tungstenProviderUuid; + + ///////////////////////////////////////////////////// + /////////////////// Accessors /////////////////////// + ///////////////////////////////////////////////////// + + @Override + public String getCommandName() { + return "listTungstenProviders"; + } + + @Override + public long getEntityOwnerId() { + return CallContext.current().getCallingAccount().getId(); + } + + public Long getTungstenProviderUuid() { + return tungstenProviderUuid; + } + + ///////////////////////////////////////////////////// + /////////////// API Implementation/////////////////// + ///////////////////////////////////////////////////// + + @Inject + private TungstenProviderService tungstenProviderService; + + @Override + public void execute() throws ResourceUnavailableException, InsufficientCapacityException, ServerApiException, ConcurrentOperationException, ResourceAllocationException, + NetworkRuleConflictException { + List providers = tungstenProviderService.listProviders(this); + + List providerList = new ArrayList<>(); + for (TungstenProviderVO provider : providers) { + TungstenProviderResponse responseObject = TungstenResponseHelper.createTungstenProviderResponse(provider); + providerList.add(responseObject); + } + ListResponse responseList = new ListResponse(); + responseList.setResponseName(getCommandName()); + responseList.setResponses(providerList); + setResponseObject(responseList); + } + +} \ No newline at end of file diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenProviderResponse.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenProviderResponse.java new file mode 100644 index 000000000000..e65c4eafe66f --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenProviderResponse.java @@ -0,0 +1,60 @@ +package org.apache.cloudstack.network.tungsten.api.response; + +import com.cloud.network.TungstenProvider; +import com.cloud.serializer.Param; +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 = {TungstenProvider.class}) +public class TungstenProviderResponse extends BaseResponse { + + @SerializedName(ApiConstants.NAME) + @Param(description = "tungsten provider name") + private String name; + + @SerializedName(ApiConstants.UUID) + @Param(description = "tungsten provider uuid") + private String uuid; + + @SerializedName(ApiConstants.TUNGSTEN_PROVIDER_HOSTNAME) + @Param(description = "tungsten provider hostname") + private String hostname; + + @SerializedName(ApiConstants.TUNGSTEN_PROVIDER_PORT) + @Param(description = "tungsten provider port") + private String port; + + public String getHostname() { + return hostname; + } + + public void setHostname(String hostname) { + this.hostname = hostname; + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public String getPort() { + return port; + } + + public void setPort(String port) { + this.port = port; + } + + public String getUuid() { + return uuid; + } + + public void setUuid(String uuid) { + this.uuid = uuid; + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java index 08c908c17392..67a05512eb91 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java @@ -30,8 +30,6 @@ public class TungstenElement extends AdapterBase implements StaticNatServiceProv @Inject NetworkModel _networkModel; - @Inject - TungstenService _tungstenService; private static final Logger s_logger = Logger.getLogger(TungstenElement.class); private final Map> _capabilities = InitCapabilities(); diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java index 721a4363a3d1..7f382f1f68cb 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java @@ -20,6 +20,7 @@ import com.cloud.vm.NicProfile; import com.cloud.vm.ReservationContext; import com.cloud.vm.VirtualMachineProfile; +import net.juniper.contrail.api.types.Project; import net.juniper.contrail.api.types.VirtualMachine; import net.juniper.contrail.api.types.VirtualMachineInterface; import net.juniper.contrail.api.types.VirtualNetwork; @@ -51,12 +52,12 @@ public Network design(NetworkOffering offering, DeploymentPlan plan, Network use PhysicalNetworkVO physnet = _physicalNetworkDao.findById(plan.getPhysicalNetworkId()); DataCenter dc = _dcDao.findById(plan.getDataCenterId()); - if(!canHandle(offering, dc.getNetworkType(),physnet)){ + if (!canHandle(offering, dc.getNetworkType(), physnet)) { s_logger.debug("Refusing to design this network"); return null; } - NetworkVO network = (NetworkVO)super.design(offering, plan, userSpecified, owner); + NetworkVO network = (NetworkVO) super.design(offering, plan, userSpecified, owner); return network; } @@ -124,7 +125,7 @@ public Network implement(Network network, NetworkOffering offering, DeployDestin s_logger.debug("Refusing to implement this network"); return null; } - NetworkVO implemented = (NetworkVO)super.implement(network, offering, + NetworkVO implemented = (NetworkVO) super.implement(network, offering, dest, context); if (network.getGateway() != null) { @@ -140,10 +141,25 @@ public Network implement(Network network, NetworkOffering offering, DeployDestin return implemented; } + @Override + public void reserve(final NicProfile nic, final Network network, final VirtualMachineProfile vm, final DeployDestination dest, final ReservationContext context) + throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + super.reserve(nic, network, vm, dest, context); + try { + String tungstenVirtualMachineUuid = createVirtualMachineInTungsten(vm.getUuid(), vm.getInstanceName()); + Project project = tungstenService.getTungstenNetworkProject(vm.getOwner()); + String tungstenVmInterfaceUuid = createVmInterfaceInTungsten(vm.getInstanceName(), project.getUuid(), + network.getUuid(), tungstenVirtualMachineUuid, null, Arrays.asList(nic.getMacAddress())); + createTungstenInstanceIp(vm.getInstanceName() + "-InstanceIp", tungstenVmInterfaceUuid, network.getUuid(), nic.getIPv4Address()); + } catch (IOException e) { + throw new CloudRuntimeException("Failed to create resources in tungsten for the network with uuid: " + vm.getUuid()); + } + } + @Override public boolean trash(Network network, NetworkOffering offering) { try { - tungstenService.deleteNetworkFromTungsten(network.getTungstenNetworkUuid()); + tungstenService.deleteNetworkFromTungsten(network.getUuid()); } catch (IOException e) { return false; } @@ -151,15 +167,14 @@ public boolean trash(Network network, NetworkOffering offering) { } @Override - public Network createNetworkInTungsten(Network networkVO) { + public void createNetworkInTungsten(Network networkVO, Account owner) throws IOException { + Project project = tungstenService.getTungstenNetworkProject(owner); List subnetIp = Arrays.asList(networkVO.getCidr().split("/")); String subnetIpPrefix = subnetIp.get(0); int subnetIpPrefixLength = Integer.parseInt(subnetIp.get(1)); boolean isDhcpEnabled = networkVO.getMode().equals(Networks.Mode.Dhcp); - VirtualNetwork virtualNetwork = tungstenService.createNetworkInTungsten(null, networkVO.getName(), null, + VirtualNetwork virtualNetwork = tungstenService.createNetworkInTungsten(networkVO.getUuid(), networkVO.getName(), project.getUuid(), null, null, null, subnetIpPrefix, subnetIpPrefixLength, networkVO.getGateway(), isDhcpEnabled, null, false); - networkVO.setTungstenNetworkUuid(virtualNetwork.getUuid()); - return networkVO; } @Override diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java index 9555329cb72d..1c8b4a80968e 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManager.java @@ -27,30 +27,30 @@ import java.io.IOException; public interface TungstenManager extends PluggableService { - ListResponse getNetworks(ListTungstenNetworkCmd cmd) throws IOException; + ListResponse getNetworks(ListTungstenNetworkCmd cmd) throws IOException; - ListResponse getVmInterfaces(ListTungstenVmInterfaceCmd cmd) - throws IOException; + ListResponse getVmInterfaces(ListTungstenVmInterfaceCmd cmd) + throws IOException; - ListResponse getVirtualMachines(ListTungstenVirtualMachineCmd cmd) - throws IOException; + ListResponse getVirtualMachines(ListTungstenVirtualMachineCmd cmd) + throws IOException; - VirtualNetwork createTungstenNetwork(CreateTungstenNetworkCmd cmd); + VirtualNetwork createTungstenNetwork(CreateTungstenNetworkCmd cmd); - VirtualMachine createTungstenVirtualMachine(CreateTungstenVirtualMachineCmd cmd); + VirtualMachine createTungstenVirtualMachine(CreateTungstenVirtualMachineCmd cmd); - VirtualMachineInterface createTungstenVirtualMachineInterface(CreateTungstenVmInterfaceCmd cmd); + VirtualMachineInterface createTungstenVirtualMachineInterface(CreateTungstenVmInterfaceCmd cmd); - InstanceIp createInstanceIp(CreateTungstenInstanceIpCmd cmd); + InstanceIp createInstanceIp(CreateTungstenInstanceIpCmd cmd); - VirtualNetwork deleteTungstenNetwork(DeleteTungstenNetworkCmd cmd) throws IOException; + VirtualNetwork deleteTungstenNetwork(DeleteTungstenNetworkCmd cmd) throws IOException; - ApiObjectBase getTungstenObjectByUUID(Class cls, String uuid) - throws IOException; + ApiObjectBase getTungstenObjectByUUID(Class cls, String uuid) + throws IOException; - SuccessResponse addVRouterPort(AddVRouterPortCmd cmd) throws IOException; + SuccessResponse addVRouterPort(AddVRouterPortCmd cmd) throws IOException; - SuccessResponse deleteVRouterPort(DeleteVRouterPortCmd cmd) throws IOException; + SuccessResponse deleteVRouterPort(DeleteVRouterPortCmd cmd) throws IOException; - ListResponse getVirtualRouters(ListTungstenVirtualRouterCmd cmd) throws IOException; + ListResponse getVirtualRouters(ListTungstenVirtualRouterCmd cmd) throws IOException; } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java index b89c5c47cc30..3f9966c5b3e2 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java @@ -15,11 +15,14 @@ import org.apache.cloudstack.network.tungsten.api.command.AddVRouterPortCmd; import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenInstanceIpCmd; import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenNetworkCmd; +import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenProviderCmd; import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenVirtualMachineCmd; import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenVmInterfaceCmd; import org.apache.cloudstack.network.tungsten.api.command.DeleteTungstenNetworkCmd; +import org.apache.cloudstack.network.tungsten.api.command.DeleteTungstenProviderCmd; import org.apache.cloudstack.network.tungsten.api.command.DeleteVRouterPortCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenNetworkCmd; +import org.apache.cloudstack.network.tungsten.api.command.ListTungstenProvidersCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVirtualMachineCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVirtualRouterCmd; import org.apache.cloudstack.network.tungsten.api.command.ListTungstenVmInterfaceCmd; @@ -40,190 +43,191 @@ @Component public class TungstenManagerImpl extends ManagerBase implements TungstenManager, Configurable { - private static final Logger s_logger = Logger.getLogger(TungstenManager.class); - - @Inject - TungstenService tungstenService; - - @Override - public List> getCommands() { - return Lists.>newArrayList(ListTungstenNetworkCmd.class, - CreateTungstenNetworkCmd.class, DeleteTungstenNetworkCmd.class, - CreateTungstenVmInterfaceCmd.class, CreateTungstenVirtualMachineCmd.class, - CreateTungstenInstanceIpCmd.class, ListTungstenVirtualMachineCmd.class, - ListTungstenVmInterfaceCmd.class, AddVRouterPortCmd.class, DeleteVRouterPortCmd.class, - ListTungstenVirtualRouterCmd.class - ); - } - - @Override - public ListResponse getNetworks(ListTungstenNetworkCmd cmd) throws IOException{ - List networks; - ListResponse response = new ListResponse<>(); - List tungstenNetworkResponses = new ArrayList<>(); - - if(cmd.getNetworkUUID() != null) - networks = Arrays.asList(tungstenService.getVirtualNetworkFromTungsten(cmd.getNetworkUUID())); - else - networks = (List) tungstenService.get_api().list(VirtualNetwork.class, null); - - if(networks != null && !networks.isEmpty()){ - for(VirtualNetwork virtualNetwork : networks){ - TungstenNetworkResponse tungstenNetworkResponse = TungstenResponseHelper.createTungstenNetworkResponse(virtualNetwork); - tungstenNetworkResponses.add(tungstenNetworkResponse); - } - } - response.setResponses(tungstenNetworkResponses); - return response; - } - - @Override - public ListResponse getVirtualRouters(ListTungstenVirtualRouterCmd cmd) throws IOException { - List virtualRouters; - ListResponse response = new ListResponse<>(); - List tungstenVirtualRouterResponses = new ArrayList<>(); - - if(cmd.getVirtualRouterUuid() != null) - virtualRouters = Arrays.asList((VirtualRouter)getTungstenObjectByUUID(VirtualRouter.class, cmd.getVirtualRouterUuid())); - else - virtualRouters = (List) tungstenService.get_api().list(VirtualRouter.class, null); - - if(virtualRouters != null & !virtualRouters.isEmpty()){ - for(VirtualRouter virtualRouter : virtualRouters){ - TungstenVirtualRouterResponse tungstenVirtualRouterResponse = TungstenResponseHelper.createTungstenVirtualRouterResponse(virtualRouter); - tungstenVirtualRouterResponses.add(tungstenVirtualRouterResponse); - } - } - response.setResponses(tungstenVirtualRouterResponses); - return response; - } - - @Override - public ListResponse getVmInterfaces(ListTungstenVmInterfaceCmd cmd) throws IOException{ - List vmInterfaces; - ListResponse response = new ListResponse<>(); - List tungstenVmInterfaceResponses = new ArrayList<>(); - - if(cmd.getVmInterfaceUUID() != null) - vmInterfaces = Arrays.asList((VirtualMachineInterface)getTungstenObjectByUUID(VirtualMachineInterface.class, cmd.getVmInterfaceUUID())); - else - vmInterfaces = (List) tungstenService.get_api().list(VirtualMachineInterface.class, null); - - if(vmInterfaces != null && !vmInterfaces.isEmpty()){ - for(VirtualMachineInterface vmInterface : vmInterfaces){ - TungstenVmInterfaceResponse tungstenVmInterfaceResponse = TungstenResponseHelper.createTungstenVmInterfaceResponse(vmInterface); - tungstenVmInterfaceResponses.add(tungstenVmInterfaceResponse); - } - } - response.setResponses(tungstenVmInterfaceResponses); - return response; - } - - public ListResponse getVirtualMachines(ListTungstenVirtualMachineCmd cmd) throws IOException{ - List virtualMachines; - ListResponse response = new ListResponse<>(); - List tungstenVirtualMachineResponses = new ArrayList<>(); - - if(cmd.getVirtualMachineUUID() != null) - virtualMachines = Arrays.asList((VirtualMachine)tungstenService.get_api().findById(VirtualMachine.class, cmd.getVirtualMachineUUID())); - else - virtualMachines = (List) tungstenService.get_api().list(VirtualMachine.class, null); - - if(virtualMachines != null && !virtualMachines.isEmpty()){ - for(VirtualMachine virtualMachine : virtualMachines){ - TungstenVirtualMachineResponse tungstenVirtualMachineResponse = TungstenResponseHelper.createTungstenVirtualMachineResponse(virtualMachine); - tungstenVirtualMachineResponses.add(tungstenVirtualMachineResponse); - } - } - response.setResponses(tungstenVirtualMachineResponses); - return response; - } - - @Override - public VirtualNetwork createTungstenNetwork(CreateTungstenNetworkCmd cmd){ - return tungstenService.createNetworkInTungsten(cmd.getTungstenNetworkUuid(), cmd.getName(), cmd.getNetworkIpamUUID(), cmd.getIpAllocPoolStart(), - cmd.getIpAllocPoolEnd(), cmd.getSubnetIpPrefix(), cmd.getSubnetIpPrefixLength(), cmd.getDefaultGateway(), cmd.isEnableDHCP(), - cmd.getDnsNameservers(), cmd.isAddrFromStart()); - } - - @Override - public VirtualMachine createTungstenVirtualMachine(CreateTungstenVirtualMachineCmd cmd){ - return tungstenService.createVmInTungsten(cmd.getTungstenVmUuid(), cmd.getName()); - } - - @Override - public InstanceIp createInstanceIp(CreateTungstenInstanceIpCmd cmd){ - return tungstenService.createInstanceIpInTungsten(cmd.getName(), cmd.getTungstenVmInterfaceUuid(), - cmd.getTungstenNetworkUuid(), cmd.getTungstenInstanceIpAddress()); - } - - @Override - public VirtualMachineInterface createTungstenVirtualMachineInterface(CreateTungstenVmInterfaceCmd cmd){ - return tungstenService.createVmInterfaceInTungsten(cmd.getName(), cmd.getTungstenProjectUuid(), cmd.getTungstenNetworkUuid(), - cmd.getTungstenVirtualMachineUuid(), cmd.getTungstenSecurityGroupUuid(), - cmd.getTungstenVmInterfaceMacAddresses()); - } - - @Override - public ApiObjectBase getTungstenObjectByUUID(Class cls, String uuid) throws IOException { - if(uuid != null) - return tungstenService.get_api().findById(cls, uuid); - else - return null; - } - - @Override - public VirtualNetwork deleteTungstenNetwork(DeleteTungstenNetworkCmd cmd) throws IOException { - return tungstenService.deleteNetworkFromTungsten(cmd.getTungstenNetworkUuid()); - } - - @Override - public SuccessResponse addVRouterPort(final AddVRouterPortCmd cmd) throws IOException { - Port port = new Port(); - port.setId(cmd.getTungstenVmInterfaceUuid()); - port.setInstanceId(cmd.getTungstenVirtualMachineUuid()); - port.setIpAddress(cmd.getTungstenInstanceIpAddress()); - port.setMacAddress(cmd.getTungstenVmInterfaceMacAddress()); - port.setTapInterfaceName(getTapName(cmd.getTungstenVmInterfaceMacAddress())); - port.setVmProjectId(String.valueOf(cmd.getProjectId())); - port.setDisplayName(cmd.getTungstenVmName()); - port.setVnId(cmd.getTungstenVnUuid()); - SuccessResponse successResponse = new SuccessResponse(cmd.getCommandName()); - if (tungstenService.get_vrouterApi().addPort(port)) { - successResponse.setSuccess(true); - successResponse.setDisplayText("Success to add vrouter port"); - } else { - successResponse.setSuccess(false); - successResponse.setDisplayText("Fail to add vrouter port"); - } - return successResponse; - } - - @Override - public SuccessResponse deleteVRouterPort(final DeleteVRouterPortCmd cmd) throws IOException { - String portId = cmd.getTungstenVmInterfaceUuid(); - SuccessResponse successResponse = new SuccessResponse(cmd.getCommandName()); - if (tungstenService.get_vrouterApi().deletePort(portId)) { - successResponse.setSuccess(true); - successResponse.setDisplayText("Success to delete vrouter port"); - } else { - successResponse.setSuccess(false); - successResponse.setDisplayText("Fail to delete vrouter port"); - } - return successResponse; - } - - @Override - public String getConfigComponentName() { - return TungstenManager.class.getSimpleName(); - } - - @Override - public ConfigKey[] getConfigKeys() { - return new ConfigKey[0]; - } - - private String getTapName(final String macAddress) { - return "tap" + macAddress.replace(":", ""); - } + private static final Logger s_logger = Logger.getLogger(TungstenManager.class); + + @Inject + TungstenService tungstenService; + + @Override + public List> getCommands() { + return Lists.>newArrayList(ListTungstenNetworkCmd.class, + CreateTungstenNetworkCmd.class, DeleteTungstenNetworkCmd.class, + CreateTungstenVmInterfaceCmd.class, CreateTungstenVirtualMachineCmd.class, + CreateTungstenInstanceIpCmd.class, ListTungstenVirtualMachineCmd.class, + ListTungstenVmInterfaceCmd.class, AddVRouterPortCmd.class, DeleteVRouterPortCmd.class, + ListTungstenVirtualRouterCmd.class, CreateTungstenProviderCmd.class, + DeleteTungstenProviderCmd.class, ListTungstenProvidersCmd.class + ); + } + + @Override + public ListResponse getNetworks(ListTungstenNetworkCmd cmd) throws IOException { + List networks; + ListResponse response = new ListResponse<>(); + List tungstenNetworkResponses = new ArrayList<>(); + + if (cmd.getNetworkUUID() != null) + networks = Arrays.asList(tungstenService.getVirtualNetworkFromTungsten(cmd.getNetworkUUID())); + else + networks = (List) tungstenService.get_api().list(VirtualNetwork.class, null); + + if (networks != null && !networks.isEmpty()) { + for (VirtualNetwork virtualNetwork : networks) { + TungstenNetworkResponse tungstenNetworkResponse = TungstenResponseHelper.createTungstenNetworkResponse(virtualNetwork); + tungstenNetworkResponses.add(tungstenNetworkResponse); + } + } + response.setResponses(tungstenNetworkResponses); + return response; + } + + @Override + public ListResponse getVirtualRouters(ListTungstenVirtualRouterCmd cmd) throws IOException { + List virtualRouters; + ListResponse response = new ListResponse<>(); + List tungstenVirtualRouterResponses = new ArrayList<>(); + + if (cmd.getVirtualRouterUuid() != null) + virtualRouters = Arrays.asList((VirtualRouter) getTungstenObjectByUUID(VirtualRouter.class, cmd.getVirtualRouterUuid())); + else + virtualRouters = (List) tungstenService.get_api().list(VirtualRouter.class, null); + + if (virtualRouters != null & !virtualRouters.isEmpty()) { + for (VirtualRouter virtualRouter : virtualRouters) { + TungstenVirtualRouterResponse tungstenVirtualRouterResponse = TungstenResponseHelper.createTungstenVirtualRouterResponse(virtualRouter); + tungstenVirtualRouterResponses.add(tungstenVirtualRouterResponse); + } + } + response.setResponses(tungstenVirtualRouterResponses); + return response; + } + + @Override + public ListResponse getVmInterfaces(ListTungstenVmInterfaceCmd cmd) throws IOException { + List vmInterfaces; + ListResponse response = new ListResponse<>(); + List tungstenVmInterfaceResponses = new ArrayList<>(); + + if (cmd.getVmInterfaceUUID() != null) + vmInterfaces = Arrays.asList((VirtualMachineInterface) getTungstenObjectByUUID(VirtualMachineInterface.class, cmd.getVmInterfaceUUID())); + else + vmInterfaces = (List) tungstenService.get_api().list(VirtualMachineInterface.class, null); + + if (vmInterfaces != null && !vmInterfaces.isEmpty()) { + for (VirtualMachineInterface vmInterface : vmInterfaces) { + TungstenVmInterfaceResponse tungstenVmInterfaceResponse = TungstenResponseHelper.createTungstenVmInterfaceResponse(vmInterface); + tungstenVmInterfaceResponses.add(tungstenVmInterfaceResponse); + } + } + response.setResponses(tungstenVmInterfaceResponses); + return response; + } + + public ListResponse getVirtualMachines(ListTungstenVirtualMachineCmd cmd) throws IOException { + List virtualMachines; + ListResponse response = new ListResponse<>(); + List tungstenVirtualMachineResponses = new ArrayList<>(); + + if (cmd.getVirtualMachineUUID() != null) + virtualMachines = Arrays.asList((VirtualMachine) tungstenService.get_api().findById(VirtualMachine.class, cmd.getVirtualMachineUUID())); + else + virtualMachines = (List) tungstenService.get_api().list(VirtualMachine.class, null); + + if (virtualMachines != null && !virtualMachines.isEmpty()) { + for (VirtualMachine virtualMachine : virtualMachines) { + TungstenVirtualMachineResponse tungstenVirtualMachineResponse = TungstenResponseHelper.createTungstenVirtualMachineResponse(virtualMachine); + tungstenVirtualMachineResponses.add(tungstenVirtualMachineResponse); + } + } + response.setResponses(tungstenVirtualMachineResponses); + return response; + } + + @Override + public VirtualNetwork createTungstenNetwork(CreateTungstenNetworkCmd cmd) { + return tungstenService.createNetworkInTungsten(cmd.getTungstenNetworkUuid(), cmd.getName(), null, cmd.getNetworkIpamUUID(), cmd.getIpAllocPoolStart(), + cmd.getIpAllocPoolEnd(), cmd.getSubnetIpPrefix(), cmd.getSubnetIpPrefixLength(), cmd.getDefaultGateway(), cmd.isEnableDHCP(), + cmd.getDnsNameservers(), cmd.isAddrFromStart()); + } + + @Override + public VirtualMachine createTungstenVirtualMachine(CreateTungstenVirtualMachineCmd cmd) { + return tungstenService.createVmInTungsten(cmd.getTungstenVmUuid(), cmd.getName()); + } + + @Override + public InstanceIp createInstanceIp(CreateTungstenInstanceIpCmd cmd) { + return tungstenService.createInstanceIpInTungsten(cmd.getName(), cmd.getTungstenVmInterfaceUuid(), + cmd.getTungstenNetworkUuid(), cmd.getTungstenInstanceIpAddress()); + } + + @Override + public VirtualMachineInterface createTungstenVirtualMachineInterface(CreateTungstenVmInterfaceCmd cmd) { + return tungstenService.createVmInterfaceInTungsten(cmd.getName(), cmd.getTungstenProjectUuid(), cmd.getTungstenNetworkUuid(), + cmd.getTungstenVirtualMachineUuid(), cmd.getTungstenSecurityGroupUuid(), + cmd.getTungstenVmInterfaceMacAddresses()); + } + + @Override + public ApiObjectBase getTungstenObjectByUUID(Class cls, String uuid) throws IOException { + if (uuid != null) + return tungstenService.get_api().findById(cls, uuid); + else + return null; + } + + @Override + public VirtualNetwork deleteTungstenNetwork(DeleteTungstenNetworkCmd cmd) throws IOException { + return tungstenService.deleteNetworkFromTungsten(cmd.getTungstenNetworkUuid()); + } + + @Override + public SuccessResponse addVRouterPort(final AddVRouterPortCmd cmd) throws IOException { + Port port = new Port(); + port.setId(cmd.getTungstenVmInterfaceUuid()); + port.setInstanceId(cmd.getTungstenVirtualMachineUuid()); + port.setIpAddress(cmd.getTungstenInstanceIpAddress()); + port.setMacAddress(cmd.getTungstenVmInterfaceMacAddress()); + port.setTapInterfaceName(getTapName(cmd.getTungstenVmInterfaceMacAddress())); + port.setVmProjectId(String.valueOf(cmd.getProjectId())); + port.setDisplayName(cmd.getTungstenVmName()); + port.setVnId(cmd.getTungstenVnUuid()); + SuccessResponse successResponse = new SuccessResponse(cmd.getCommandName()); + if (tungstenService.get_vrouterApi().addPort(port)) { + successResponse.setSuccess(true); + successResponse.setDisplayText("Success to add vrouter port"); + } else { + successResponse.setSuccess(false); + successResponse.setDisplayText("Fail to add vrouter port"); + } + return successResponse; + } + + @Override + public SuccessResponse deleteVRouterPort(final DeleteVRouterPortCmd cmd) throws IOException { + String portId = cmd.getTungstenVmInterfaceUuid(); + SuccessResponse successResponse = new SuccessResponse(cmd.getCommandName()); + if (tungstenService.get_vrouterApi().deletePort(portId)) { + successResponse.setSuccess(true); + successResponse.setDisplayText("Success to delete vrouter port"); + } else { + successResponse.setSuccess(false); + successResponse.setDisplayText("Fail to delete vrouter port"); + } + return successResponse; + } + + @Override + public String getConfigComponentName() { + return TungstenManager.class.getSimpleName(); + } + + @Override + public ConfigKey[] getConfigKeys() { + return new ConfigKey[0]; + } + + private String getTapName(final String macAddress) { + return "tap" + macAddress.replace(":", ""); + } } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderService.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderService.java new file mode 100644 index 000000000000..d0b3f03795e0 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderService.java @@ -0,0 +1,22 @@ +package org.apache.cloudstack.network.tungsten.service; + +import com.cloud.network.TungstenProvider; +import com.cloud.network.element.TungstenProviderVO; +import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenProviderCmd; +import org.apache.cloudstack.network.tungsten.api.command.DeleteTungstenProviderCmd; +import org.apache.cloudstack.network.tungsten.api.command.ListTungstenProvidersCmd; + +import javax.naming.ConfigurationException; +import java.util.List; + +public interface TungstenProviderService { + TungstenProvider addProvider(CreateTungstenProviderCmd cmd) throws ConfigurationException; + + TungstenProviderVO getTungstenProvider(); + + void deleteTungstenProvider(DeleteTungstenProviderCmd cmd); + + List listProviders(ListTungstenProvidersCmd cmd); + + void disableTungstenNsp(); +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderServiceImpl.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderServiceImpl.java new file mode 100644 index 000000000000..ce703634b886 --- /dev/null +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderServiceImpl.java @@ -0,0 +1,105 @@ +package org.apache.cloudstack.network.tungsten.service; + +import com.cloud.event.ActionEvent; +import com.cloud.event.EventTypes; +import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.Network; +import com.cloud.network.PhysicalNetworkServiceProvider; +import com.cloud.network.TungstenProvider; +import com.cloud.network.dao.PhysicalNetworkServiceProviderDao; +import com.cloud.network.dao.PhysicalNetworkServiceProviderVO; +import com.cloud.network.dao.TungstenProviderDao; +import com.cloud.network.element.TungstenProviderVO; +import org.apache.cloudstack.api.ApiErrorCode; +import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.network.tungsten.api.command.CreateTungstenProviderCmd; +import org.apache.cloudstack.network.tungsten.api.command.DeleteTungstenProviderCmd; +import org.apache.cloudstack.network.tungsten.api.command.ListTungstenProvidersCmd; +import org.apache.log4j.Logger; +import org.springframework.stereotype.Component; + +import javax.inject.Inject; +import javax.naming.ConfigurationException; +import java.io.IOException; +import java.net.HttpURLConnection; +import java.net.URL; +import java.util.ArrayList; +import java.util.List; + +@Component +public class TungstenProviderServiceImpl implements TungstenProviderService { + + private static final Logger s_logger = Logger.getLogger(TungstenProviderServiceImpl.class); + + @Inject + TungstenProviderDao _tungstenProviderDao; + @Inject + TungstenService _tungstenService; + @Inject + PhysicalNetworkServiceProviderDao _physicalNetworkServiceProviderDao; + + @Override + public TungstenProvider addProvider(CreateTungstenProviderCmd cmd) throws ConfigurationException { + checkProviderConnection(cmd); + TungstenProviderVO element = _tungstenProviderDao.findByNspId(cmd.getNspId()); + if (element != null) { + s_logger.debug("There is already a tungsten provider with service network provider id " + cmd.getNspId()); + return null; + } + element = new TungstenProviderVO(cmd.getNspId(), cmd.getName(), cmd.getPort(), cmd.getHostname()); + _tungstenProviderDao.persist(element); + _tungstenService.init(); + return element; + } + + @Override + public TungstenProviderVO getTungstenProvider() { + PhysicalNetworkServiceProviderVO provider = _physicalNetworkServiceProviderDao.findByProviderName(Network.Provider.Tungsten.getName()); + TungstenProviderVO tungstenProvider = _tungstenProviderDao.findByNspId(provider.getId()); + return tungstenProvider; + } + + @Override + @ActionEvent(eventType = EventTypes.EVENT_TUNGSTEN_DELETE_PROVIDER, eventDescription = "Delete tungsten provider", async = true) + public void deleteTungstenProvider(DeleteTungstenProviderCmd cmd) { + if (_tungstenProviderDao.findByUuid(cmd.getTungstenProviderUuid()) == null) + throw new InvalidParameterValueException("Tungsten provider not found with the uuid: " + cmd.getTungstenProviderUuid()); + _tungstenProviderDao.deleteProviderByUuid(cmd.getTungstenProviderUuid()); + disableTungstenNsp(); + } + + @Override + public List listProviders(ListTungstenProvidersCmd cmd) { + if (cmd.getTungstenProviderUuid() != null) { + List tungstenProviders = new ArrayList(); + TungstenProviderVO tungstenProvider = _tungstenProviderDao.findById(cmd.getTungstenProviderUuid()); + if (tungstenProvider != null) { + tungstenProviders.add(tungstenProvider); + } + return tungstenProviders; + } + return _tungstenProviderDao.listAll(); + } + + @Override + public void disableTungstenNsp() { + PhysicalNetworkServiceProviderVO networkServiceProvider = _physicalNetworkServiceProviderDao.findByProviderName(Network.Provider.Tungsten.getName()); + networkServiceProvider.setState(PhysicalNetworkServiceProvider.State.Disabled); + _physicalNetworkServiceProviderDao.update(networkServiceProvider.getId(), networkServiceProvider); + } + + public void checkProviderConnection(CreateTungstenProviderCmd cmd) { + try { + URL url = new URL("http://" + cmd.getHostname() + ":" + cmd.getPort()); + HttpURLConnection huc = (HttpURLConnection) url.openConnection(); + + if (huc.getResponseCode() != 200) { + throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, + "There is not a tungsten provider using hostname: " + cmd.getHostname() + " and port: " + cmd.getPort()); + } + } catch (IOException e) { + throw new ServerApiException(ApiErrorCode.RESOURCE_UNAVAILABLE_ERROR, + "There is not a tungsten provider using hostname: " + cmd.getHostname() + " and port: " + cmd.getPort()); + } + } +} diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java index 9a9b67993080..4a07197a39f6 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java @@ -1,5 +1,6 @@ package org.apache.cloudstack.network.tungsten.service; +import com.cloud.network.element.TungstenProviderVO; import net.juniper.contrail.api.ApiPropertyBase; import net.juniper.contrail.api.ObjectReference; import net.juniper.contrail.api.types.InstanceIp; @@ -9,13 +10,14 @@ import net.juniper.contrail.api.types.VirtualRouter; import org.apache.cloudstack.network.tungsten.api.response.TungstenInstanceIpResponse; import org.apache.cloudstack.network.tungsten.api.response.TungstenNetworkResponse; +import org.apache.cloudstack.network.tungsten.api.response.TungstenProviderResponse; import org.apache.cloudstack.network.tungsten.api.response.TungstenVirtualMachineResponse; import org.apache.cloudstack.network.tungsten.api.response.TungstenVirtualRouterResponse; import org.apache.cloudstack.network.tungsten.api.response.TungstenVmInterfaceResponse; public class TungstenResponseHelper { - public static TungstenNetworkResponse createTungstenNetworkResponse(VirtualNetwork virtualNetwork){ + public static TungstenNetworkResponse createTungstenNetworkResponse(VirtualNetwork virtualNetwork) { TungstenNetworkResponse tungstenNetworkResponse = new TungstenNetworkResponse(); tungstenNetworkResponse.setName(virtualNetwork.getName()); tungstenNetworkResponse.setParentUuid(virtualNetwork.getParentUuid()); @@ -25,13 +27,13 @@ public static TungstenNetworkResponse createTungstenNetworkResponse(VirtualNetwo return tungstenNetworkResponse; } - public static TungstenVirtualMachineResponse createTungstenVirtualMachineResponse(VirtualMachine virtualMachine){ + public static TungstenVirtualMachineResponse createTungstenVirtualMachineResponse(VirtualMachine virtualMachine) { TungstenVirtualMachineResponse tungstenVirtualMachineResponse = new TungstenVirtualMachineResponse(); tungstenVirtualMachineResponse.setName(virtualMachine.getName()); tungstenVirtualMachineResponse.setUuid(virtualMachine.getUuid()); - if(virtualMachine.getVirtualMachineInterfaceBackRefs() != null){ - for(ObjectReference item : virtualMachine.getVirtualMachineInterfaceBackRefs()){ + if (virtualMachine.getVirtualMachineInterfaceBackRefs() != null) { + for (ObjectReference item : virtualMachine.getVirtualMachineInterfaceBackRefs()) { tungstenVirtualMachineResponse.getVmInterfacesUuid().add(item.getUuid()); } } @@ -40,20 +42,20 @@ public static TungstenVirtualMachineResponse createTungstenVirtualMachineRespons return tungstenVirtualMachineResponse; } - public static TungstenVmInterfaceResponse createTungstenVmInterfaceResponse(VirtualMachineInterface virtualMachineInterface){ + public static TungstenVmInterfaceResponse createTungstenVmInterfaceResponse(VirtualMachineInterface virtualMachineInterface) { TungstenVmInterfaceResponse tungstenVmInterfaceResponse = new TungstenVmInterfaceResponse(); tungstenVmInterfaceResponse.setName(virtualMachineInterface.getName()); tungstenVmInterfaceResponse.setUuid(virtualMachineInterface.getUuid()); tungstenVmInterfaceResponse.setParentUuid(virtualMachineInterface.getParentUuid()); - if(virtualMachineInterface.getVirtualNetwork() != null) { - for(ObjectReference item : virtualMachineInterface.getVirtualNetwork()){ + if (virtualMachineInterface.getVirtualNetwork() != null) { + for (ObjectReference item : virtualMachineInterface.getVirtualNetwork()) { tungstenVmInterfaceResponse.getVirtualNetworksUuid().add(item.getUuid()); } } - if(virtualMachineInterface.getVirtualMachine() != null){ - for(ObjectReference item : virtualMachineInterface.getVirtualMachine()){ + if (virtualMachineInterface.getVirtualMachine() != null) { + for (ObjectReference item : virtualMachineInterface.getVirtualMachine()) { tungstenVmInterfaceResponse.getVirtualMachinesUuid().add(item.getUuid()); } } @@ -61,7 +63,7 @@ public static TungstenVmInterfaceResponse createTungstenVmInterfaceResponse(Virt return tungstenVmInterfaceResponse; } - public static TungstenVirtualRouterResponse createTungstenVirtualRouterResponse(VirtualRouter virtualRouter){ + public static TungstenVirtualRouterResponse createTungstenVirtualRouterResponse(VirtualRouter virtualRouter) { TungstenVirtualRouterResponse tungstenVirtualRouterResponse = new TungstenVirtualRouterResponse(); tungstenVirtualRouterResponse.setUuid(virtualRouter.getUuid()); tungstenVirtualRouterResponse.setName(virtualRouter.getName()); @@ -69,10 +71,20 @@ public static TungstenVirtualRouterResponse createTungstenVirtualRouterResponse( return tungstenVirtualRouterResponse; } - public static TungstenInstanceIpResponse createTungstenInstanceIpResponse(InstanceIp instanceIp){ + public static TungstenInstanceIpResponse createTungstenInstanceIpResponse(InstanceIp instanceIp) { TungstenInstanceIpResponse tungstenInstanceIpResponse = new TungstenInstanceIpResponse(); tungstenInstanceIpResponse.setName(instanceIp.getName()); tungstenInstanceIpResponse.setObjectName("tungstenInstanceIp"); return tungstenInstanceIpResponse; } + + public static TungstenProviderResponse createTungstenProviderResponse(TungstenProviderVO tungstenProviderVO) { + TungstenProviderResponse tungstenProviderResponse = new TungstenProviderResponse(); + tungstenProviderResponse.setHostname(tungstenProviderVO.getHostname()); + tungstenProviderResponse.setName(tungstenProviderVO.getProviderName()); + tungstenProviderResponse.setPort(tungstenProviderVO.getPort()); + tungstenProviderResponse.setUuid(tungstenProviderVO.getUuid()); + tungstenProviderResponse.setObjectName("tungstenProvider"); + return tungstenProviderResponse; + } } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenService.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenService.java index 4572653f5126..d9f35b57b767 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenService.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenService.java @@ -1,22 +1,30 @@ package org.apache.cloudstack.network.tungsten.service; +import com.cloud.user.Account; import net.juniper.contrail.api.ApiConnector; import net.juniper.contrail.api.types.InstanceIp; +import net.juniper.contrail.api.types.Project; import net.juniper.contrail.api.types.VirtualMachine; import net.juniper.contrail.api.types.VirtualMachineInterface; import net.juniper.contrail.api.types.VirtualNetwork; import org.apache.cloudstack.network.tungsten.vrouter.VRouterApiConnector; +import javax.naming.ConfigurationException; import java.io.IOException; import java.util.List; public interface TungstenService { + public static final String TUNGSTEN_DEFAULT_DOMAIN = "default-domain"; + public static final String TUNGSTEN_DEFAULT_PROJECT = "default-project"; + + void init() throws ConfigurationException; + ApiConnector get_api(); VRouterApiConnector get_vrouterApi(); - VirtualNetwork createNetworkInTungsten(String networkUuid, String networkName, String networkIpamUuid, String ipAllocPoolStart, + VirtualNetwork createNetworkInTungsten(String networkUuid, String networkName, String projectUuid, String networkIpamUuid, String ipAllocPoolStart, String ipAllocPoolEnd, String subnetIpPrefix, int subnetIpPrefixLength, String defaultGateway, boolean isDhcpEnabled, List dnsNameservers, boolean isIpAddrFromStart); @@ -33,4 +41,7 @@ VirtualMachineInterface createVmInterfaceInTungsten(String vmInterfaceName, Stri VirtualNetwork getVirtualNetworkFromTungsten(String virtualNetworkUuid) throws IOException; void expugeVmFromTungsten(String vmUuid) throws IOException; + + Project getTungstenNetworkProject(Account owner) throws IOException; + } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImpl.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImpl.java index cfd2f23cf4c4..f3d6f7838f6c 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImpl.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImpl.java @@ -1,10 +1,20 @@ package org.apache.cloudstack.network.tungsten.service; +import com.cloud.domain.DomainVO; +import com.cloud.domain.dao.DomainDao; import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.element.TungstenProviderVO; +import com.cloud.projects.ProjectVO; +import com.cloud.projects.dao.ProjectDao; +import com.cloud.user.Account; +import com.cloud.user.dao.AccountDao; import com.cloud.utils.PropertiesUtil; import net.juniper.contrail.api.ApiConnector; import net.juniper.contrail.api.ApiConnectorFactory; import net.juniper.contrail.api.ApiObjectBase; +import net.juniper.contrail.api.ApiPropertyBase; +import net.juniper.contrail.api.ObjectReference; +import net.juniper.contrail.api.types.Domain; import net.juniper.contrail.api.types.InstanceIp; import net.juniper.contrail.api.types.MacAddressesType; import net.juniper.contrail.api.types.NetworkIpam; @@ -24,6 +34,7 @@ import org.springframework.stereotype.Component; import javax.annotation.PostConstruct; +import javax.inject.Inject; import javax.naming.ConfigurationException; import java.io.File; import java.io.FileInputStream; @@ -43,6 +54,16 @@ public class TungstenServiceImpl implements TungstenService { private final String configuration = "plugins/network-elements/tungsten/conf/tungsten.properties"; private VRouterApiConnector _vrouterApi; + @Inject + ProjectDao _projectDao; + @Inject + AccountDao _accountDao; + @Inject + DomainDao _domainDao; + @Inject + TungstenProviderService _tungstenProviderService; + + public ApiConnector get_api() { return _api; } @@ -52,50 +73,55 @@ public VRouterApiConnector get_vrouterApi() { } @PostConstruct + @Override public void init() throws ConfigurationException { File configFile = PropertiesUtil.findConfigFile(configuration); - FileInputStream fileStream = null; - try { - String hostname = null; - int port = 0; - String vrouterHost = null; - String vrouterPort = null; - if (configFile == null) { - throw new FileNotFoundException("Tungsten config file not found!"); - } else { - final Properties configProps = new Properties(); - fileStream = new FileInputStream(configFile); - configProps.load(fileStream); - - hostname = configProps.getProperty("tungsten.api.hostname"); - String portStr = configProps.getProperty("tungsten.api.port"); - if (portStr != null && portStr.length() > 0) { - port = Integer.parseInt(portStr); - } + TungstenProviderVO tungstenProvider = _tungstenProviderService.getTungstenProvider(); + if (tungstenProvider != null) { + FileInputStream fileStream = null; + try { + String vrouterHost = null; + String vrouterPort = null; + String hostname = null; + int port = 0; + if (configFile == null) { + throw new FileNotFoundException("Tungsten config file not found!"); + } else { + final Properties configProps = new Properties(); + fileStream = new FileInputStream(configFile); + configProps.load(fileStream); + + vrouterHost = configProps.getProperty("tungsten.vrouter.hostname"); + vrouterPort = configProps.getProperty("tungsten.vrouter.port"); + hostname = tungstenProvider.getHostname(); + port = Integer.parseInt(tungstenProvider.getPort()); - vrouterHost = configProps.getProperty("tungsten.vrouter.hostname"); - vrouterPort = configProps.getProperty("tungsten.vrouter.port"); + } + _api = ApiConnectorFactory.build(hostname, port); + _vrouterApi = VRouterApiConnectorFactory.getInstance(vrouterHost, vrouterPort); + } catch (Exception ex) { + s_logger.debug("Exception in configure: " + ex); + ex.printStackTrace(); + throw new ConfigurationException(); + } finally { + IOUtils.closeQuietly(fileStream); } - _api = ApiConnectorFactory.build(hostname, port); - _vrouterApi = VRouterApiConnectorFactory.getInstance(vrouterHost, vrouterPort); - } catch (IOException ex) { - s_logger.warn("Unable to read " + configuration, ex); - throw new ConfigurationException(); - } catch (Exception ex) { - s_logger.debug("Exception in configure: " + ex); - ex.printStackTrace(); - throw new ConfigurationException(); - } finally { - IOUtils.closeQuietly(fileStream); + } else { + _tungstenProviderService.disableTungstenNsp(); } } @Override - public VirtualNetwork createNetworkInTungsten(String networkUuid, String networkName, String networkIpamUuid, String ipAllocPoolStart, + public VirtualNetwork createNetworkInTungsten(String networkUuid, String networkName, String projectUuid, String networkIpamUuid, String ipAllocPoolStart, String ipAllocPoolEnd, String subnetIpPrefix, int subnetIpPrefixLength, String defaultGateway, - boolean isDhcpEnabled, List dnsNameservers, boolean isIpAddrFromStart){ + boolean isDhcpEnabled, List dnsNameservers, boolean isIpAddrFromStart) { VirtualNetwork network = new VirtualNetwork(); try { + if (projectUuid != null) { + Project project = (Project) _api.findById(Project.class, projectUuid); + network.setParent(project); + } + network.setUuid(networkUuid); network.setName(networkName); network.setNetworkIpam(getNetworkIpam(networkName, networkIpamUuid), getVnSubnetsType(ipAllocPoolStart, ipAllocPoolEnd, subnetIpPrefix, subnetIpPrefixLength, defaultGateway, isDhcpEnabled, dnsNameservers, isIpAddrFromStart)); @@ -109,19 +135,18 @@ public VirtualNetwork createNetworkInTungsten(String networkUuid, String network @Override public VirtualNetwork deleteNetworkFromTungsten(String tungstenNetworkUuid) throws IOException { - VirtualNetwork network = (VirtualNetwork)_api.findById(VirtualNetwork.class, tungstenNetworkUuid); - if(network != null) { - if(network.getVirtualMachineInterfaceBackRefs() != null) + VirtualNetwork network = (VirtualNetwork) _api.findById(VirtualNetwork.class, tungstenNetworkUuid); + if (network != null) { + if (network.getVirtualMachineInterfaceBackRefs() != null) throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete network"); _api.delete(network); return network; - } - else + } else throw new InvalidParameterValueException("Unable to find tungsten network with UUID: " + tungstenNetworkUuid); } @Override - public VirtualMachine createVmInTungsten(String vmUuid, String vmName){ + public VirtualMachine createVmInTungsten(String vmUuid, String vmName) { VirtualMachine virtualMachine = new VirtualMachine(); try { virtualMachine.setName(vmName); @@ -136,15 +161,15 @@ public VirtualMachine createVmInTungsten(String vmUuid, String vmName){ @Override public InstanceIp createInstanceIpInTungsten(String instanceIpName, String tungstenVmInterfaceUuid, String tungstenNetworkUuid, - String tungstenInstanceIpAddress){ + String tungstenInstanceIpAddress) { InstanceIp instanceIp = new InstanceIp(); - try{ + try { instanceIp.setName(instanceIpName); VirtualMachineInterface virtualMachineInterface = (VirtualMachineInterface) _api.findById(VirtualMachineInterface.class, tungstenVmInterfaceUuid); VirtualNetwork virtualNetwork = (VirtualNetwork) _api.findById(VirtualNetwork.class, tungstenNetworkUuid); - if(virtualNetwork != null) + if (virtualNetwork != null) instanceIp.setVirtualNetwork(virtualNetwork); - if(virtualMachineInterface != null) + if (virtualMachineInterface != null) instanceIp.setVirtualMachineInterface(virtualMachineInterface); instanceIp.setAddress(tungstenInstanceIpAddress); _api.create(instanceIp); @@ -157,7 +182,7 @@ public InstanceIp createInstanceIpInTungsten(String instanceIpName, String tungs @Override public VirtualMachineInterface createVmInterfaceInTungsten(String vmInterfaceName, String tungstenProjectUuid, String tungstenNetworkUuid, - String tungstenVmUuid, String tungstenSecurityGroupUuid, List tungstenVmInterfaceMacAddresses){ + String tungstenVmUuid, String tungstenSecurityGroupUuid, List tungstenVmInterfaceMacAddresses) { VirtualMachineInterface virtualMachineInterface = new VirtualMachineInterface(); try { virtualMachineInterface.setName(vmInterfaceName); @@ -165,15 +190,15 @@ public VirtualMachineInterface createVmInterfaceInTungsten(String vmInterfaceNam VirtualNetwork virtualNetwork = (VirtualNetwork) _api.findById(VirtualNetwork.class, tungstenNetworkUuid); VirtualMachine virtualMachine = (VirtualMachine) _api.findById(VirtualMachine.class, tungstenVmUuid); SecurityGroup securityGroup = (SecurityGroup) _api.findById(SecurityGroup.class, tungstenSecurityGroupUuid); - if(virtualNetwork != null) + if (virtualNetwork != null) virtualMachineInterface.setVirtualNetwork(virtualNetwork); - if(virtualMachine != null) + if (virtualMachine != null) virtualMachineInterface.setVirtualMachine(virtualMachine); - if(securityGroup != null) + if (securityGroup != null) virtualMachineInterface.setSecurityGroup(securityGroup); - if(project != null) + if (project != null) virtualMachineInterface.setParent(project); - if(tungstenVmInterfaceMacAddresses != null && !tungstenVmInterfaceMacAddresses.isEmpty()) + if (tungstenVmInterfaceMacAddresses != null && !tungstenVmInterfaceMacAddresses.isEmpty()) virtualMachineInterface.setMacAddresses(new MacAddressesType(tungstenVmInterfaceMacAddresses)); _api.create(virtualMachineInterface); return (VirtualMachineInterface) _api.findByFQN(VirtualMachineInterface.class, getFqnName(virtualMachineInterface)); @@ -185,26 +210,37 @@ public VirtualMachineInterface createVmInterfaceInTungsten(String vmInterfaceNam @Override public VirtualNetwork getVirtualNetworkFromTungsten(String virtualNetworkUuid) throws IOException { - return (VirtualNetwork)_api.findById(VirtualNetwork.class, virtualNetworkUuid); + return (VirtualNetwork) _api.findById(VirtualNetwork.class, virtualNetworkUuid); } @Override public void expugeVmFromTungsten(String vmUuid) throws IOException { VirtualMachine virtualMachine = (VirtualMachine) _api.findById(VirtualMachine.class, vmUuid); - if(virtualMachine == null) + if (virtualMachine == null) return; - if(virtualMachine.getVirtualMachineInterfaceBackRefs() != null && virtualMachine.getVirtualMachineInterfaceBackRefs().size() > 0) { - VirtualMachineInterface virtualMachineInterface = (VirtualMachineInterface) _api.findById(VirtualMachineInterface.class, virtualMachine.getVirtualMachineInterfaceBackRefs().get(0).getUuid()); - _api.delete(VirtualMachineInterface.class, virtualMachineInterface.getUuid()); + if (virtualMachine.getVirtualMachineInterfaceBackRefs() != null && !virtualMachine.getVirtualMachineInterfaceBackRefs().isEmpty()) { + removeVirtualMachineInterfaceBackRefs(virtualMachine.getVirtualMachineInterfaceBackRefs()); } _api.delete(VirtualMachine.class, virtualMachine.getUuid()); } + public void removeVirtualMachineInterfaceBackRefs(List> virtualMachineInterfaceBackRefs) throws IOException { + for (ObjectReference item : virtualMachineInterfaceBackRefs) { + VirtualMachineInterface virtualMachineInterface = (VirtualMachineInterface) _api.findById(VirtualMachineInterface.class, item.getUuid()); + if (virtualMachineInterface.getInstanceIpBackRefs() != null && !virtualMachineInterface.getInstanceIpBackRefs().isEmpty()) { + for (ObjectReference instanceIp : virtualMachineInterface.getInstanceIpBackRefs()) { + _api.delete(InstanceIp.class, instanceIp.getUuid()); + } + } + _api.delete(VirtualMachineInterface.class, virtualMachineInterface.getUuid()); + } + } + public VnSubnetsType getVnSubnetsType(String ipAllocPoolStart, String ipAllocPoolEnd, String subnetIpPrefix, int subnetIpPrefixLength, String defaultGateway, - boolean isDhcpEnabled, List dnsNameservers, boolean isIpAddrFromStart){ + boolean isDhcpEnabled, List dnsNameservers, boolean isIpAddrFromStart) { List allocationPoolTypes = new ArrayList<>(); - if(ipAllocPoolStart != null && ipAllocPoolEnd != null) { + if (ipAllocPoolStart != null && ipAllocPoolEnd != null) { allocationPoolTypes.add(new VnSubnetsType.IpamSubnetType.AllocationPoolType(ipAllocPoolStart, ipAllocPoolEnd)); } VnSubnetsType.IpamSubnetType ipamSubnetType = new VnSubnetsType.IpamSubnetType( @@ -214,9 +250,9 @@ public VnSubnetsType getVnSubnetsType(String ipAllocPoolStart, } public NetworkIpam getNetworkIpam(String networkName, String networkIpamUuid) throws IOException { - if(networkIpamUuid != null){ + if (networkIpamUuid != null) { NetworkIpam networkIpam = (NetworkIpam) _api.findById(NetworkIpam.class, networkIpamUuid); - if(networkIpam != null) + if (networkIpam != null) return networkIpam; } NetworkIpam networkIpam = new NetworkIpam(); @@ -225,13 +261,140 @@ public NetworkIpam getNetworkIpam(String networkName, String networkIpamUuid) th return (NetworkIpam) _api.findByFQN(NetworkIpam.class, getFqnName(networkIpam)); } - public String getFqnName(ApiObjectBase obj){ + /** + * Get the tungsten project that match the project from cloudstack + * + * @param owner + * @return + * @throws IOException + */ + @Override + public Project getTungstenNetworkProject(Account owner) throws IOException { + ProjectVO cloudstackProject = getProject(owner.getAccountId()); + DomainVO cloudstackDomain = getDomain(owner.getDomainId()); + Domain tungstenDomain; + Project tungstenProject; + //get the tungsten domain + if (cloudstackDomain != null) { + tungstenDomain = (Domain) _api.findById(Domain.class, cloudstackDomain.getUuid()); + if (tungstenDomain == null) { + tungstenDomain = createDomainInTungsten(cloudstackDomain.getName(), cloudstackDomain.getUuid()); + } + } else { + tungstenDomain = getDefaultTungstenDomain(); + } + //get the tungsten project + if (cloudstackProject != null) { + tungstenProject = (Project) _api.findById(Project.class, cloudstackProject.getUuid()); + if (tungstenProject == null) { + tungstenProject = createProjectInTungsten(cloudstackProject.getName(), cloudstackProject.getUuid(), tungstenDomain); + } + } else { + tungstenProject = getDefaultTungstenProject(tungstenDomain.getName()); + } + return tungstenProject; + } + + /** + * Create a project in tungsten that match the project from cloudstack + * + * @param projectName + * @param projectUuid + * @param tungstenDomain + * @return the project created in tungsten + * @throws IOException + */ + public Project createProjectInTungsten(String projectName, String projectUuid, Domain tungstenDomain) throws IOException { + Project tungstenProject = new Project(); + tungstenProject.setDisplayName(projectName); + tungstenProject.setName(projectName); + tungstenProject.setUuid(projectUuid); + tungstenProject.setParent(tungstenDomain); + _api.create(tungstenProject); + return tungstenProject; + } + + /** + * Create a domain in tungsten that match the domain from cloudstack + * + * @param domainName + * @param domainUuid + * @return the domain created in tungsten + * @throws IOException + */ + public Domain createDomainInTungsten(String domainName, String domainUuid) throws IOException { + Domain tungstenDomain = new Domain(); + tungstenDomain.setDisplayName(domainName); + tungstenDomain.setName(domainName); + tungstenDomain.setUuid(domainUuid); + _api.create(tungstenDomain); + return tungstenDomain; + } + + public ProjectVO getProject(long accountId) { + Account account = _accountDao.findById(accountId); + if (account.getType() == Account.ACCOUNT_TYPE_PROJECT) { + return _projectDao.findByProjectAccountId(account.getId()); + } + return null; + } + + public DomainVO getDomain(long domainId) { + return _domainDao.findById(domainId); + } + + /** + * Create a default project in tungsten for a specific domain + * + * @param tungstenDomain + * @return + * @throws IOException + */ + public Project createDefaultProject(String tungstenDomain) throws IOException { + Domain domain = (Domain) _api.findByFQN(Domain.class, tungstenDomain); + Project project = new Project(); + project.setParent(domain); + project.setName(tungstenDomain + "-default-project"); + _api.create(project); + return (Project) _api.findByFQN(Project.class, tungstenDomain + ":" + project.getName()); + } + + /** + * Get the tungsten domain default project + * + * @param tungstenDomain + * @return + * @throws IOException + */ + public Project getDefaultTungstenProject(String tungstenDomain) throws IOException { + Project project; + if (tungstenDomain == null) + project = (Project) _api.findByFQN(Project.class, TUNGSTEN_DEFAULT_DOMAIN + ":" + TUNGSTEN_DEFAULT_PROJECT); + else + project = (Project) _api.findByFQN(Project.class, tungstenDomain + ":" + tungstenDomain + "-default-project"); + if (project == null) + project = createDefaultProject(tungstenDomain); + return project; + } + + /** + * Get the default domain from tungsten + * + * @return + * @throws IOException + */ + public Domain getDefaultTungstenDomain() throws IOException { + Domain domain = (Domain) _api.findByFQN(Domain.class, TUNGSTEN_DEFAULT_DOMAIN); + return domain; + } + + public String getFqnName(ApiObjectBase obj) { StringBuilder sb = new StringBuilder(); - for(String item : obj.getQualifiedName()){ + for (String item : obj.getQualifiedName()) { sb.append(item); sb.append(":"); } - sb.deleteCharAt(sb.toString().length()-1); + sb.deleteCharAt(sb.toString().length() - 1); return sb.toString(); } } diff --git a/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/spring-tungsten-context.xml b/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/spring-tungsten-context.xml index 6e5544e0d377..67c77e7f2f14 100644 --- a/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/spring-tungsten-context.xml +++ b/plugins/network-elements/tungsten/src/main/resources/META-INF/cloudstack/tungsten/spring-tungsten-context.xml @@ -31,6 +31,9 @@ + + diff --git a/tools/apidoc/gen_toc.py b/tools/apidoc/gen_toc.py index c891621d6778..3c3f2cc69238 100644 --- a/tools/apidoc/gen_toc.py +++ b/tools/apidoc/gen_toc.py @@ -89,9 +89,13 @@ 'addGloboDnsHost': 'Network', 'createTungstenVmInterface' : 'Tungsten', 'createTungstenInstanceIp' : 'Tungsten', + 'createTungstenController' : 'Tungsten', + 'createTungstenProvider' : 'Tungsten', + 'deleteTungstenProvider' : 'Tungsten', 'listTungstenVirtualMachines' : 'Tungsten', 'listTungstenVmInterfaces' : 'Tungsten', 'listTungstenVirtualRouters' : 'Tungsten', + 'listTungstenProviders' : 'Tungsten', 'Vpn': 'VPN', 'Limit': 'Limit', 'ResourceCount': 'Limit', diff --git a/ui/l10n/en.js b/ui/l10n/en.js index 52c7b256f2cd..50a504ad1dc0 100644 --- a/ui/l10n/en.js +++ b/ui/l10n/en.js @@ -1928,6 +1928,13 @@ var dictionary = { "label.vpc.supportsregionlevelvpc":"Supports Region Level VPC", "label.vpc.virtual.router":"VPC Virtual Router", "label.tungsten":"TUNGSTEN", + "label.tungsten.add.provider":"Add tungsten provider", + "label.tungsten.providers":"Tungsten providers", + "label.tungsten.providerdetail":"Tungsten Provider Details", + "label.tungsten.delete.provider":"Delete tungsten provider", + "label.tungsten.provider.hostname":"Provider hostname", + "label.tungsten.provider.port":"Provider port", + "label.tungsten.action.delete.provider":"Delete provider", "label.vpn":"VPN", "label.vpn.customer.gateway":"VPN Customer Gateway", "label.vpn.force.encapsulation":"Force UDP Encapsulation of ESP Packets", @@ -2003,6 +2010,7 @@ var dictionary = { "message.action.delete.template":"Please confirm that you want to delete this template.", "message.action.delete.template.for.all.zones":"The template is used by all zones. Please confirm that you want to delete it from all zones.", "message.action.delete.volume":"Please confirm that you want to delete this volume.", + "message.action.delete.provider":"Please confirm that you want to delete this provider.", "message.action.delete.vpn.user":"Please confirm that you want to delete the VPN user.", "message.action.delete.zone":"Please confirm that you want to delete this zone.", "message.action.destroy.instance":"Please confirm that you want to destroy this instance.", diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 5bd461a4a2be..0a942f6c3a3f 100755 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -4818,22 +4818,8 @@ label: 'label.tungsten', isMaximized: true, type: 'detailView', - fields: { - name: { - label: 'label.name' - }, - ipaddress: { - label: 'label.ip.address' - }, - state: { - label: 'label.status', - indicator: { - 'Enabled': 'on' - } - } - }, tabs: { - network: { + details: { title: 'label.network', fields:[ { name: { @@ -4860,11 +4846,212 @@ dataProvider: function (args) { refreshNspData("Tungsten"); args.response.success({ - actionFilter: virtualRouterProviderActionFilter, data: $.extend(nspMap[ "Tungsten"], { supportedServices: nspMap[ "Tungsten"].servicelist.join(', ') - }) + }), + actionFilter: networkProviderActionFilter('Tungsten') + }); + } + }, + controllers: { + title: 'label.tungsten.providers', + listView: { + id: 'tungstenProviderList', + fields: { + name: { + label: 'label.name' + }, + tungstenproviderhostname: { + label: 'label.tungsten.provider.hostname' + }, + tungstenproviderport: { + label: 'label.tungsten.provider.port' + } + }, + dataProvider: function (args) { + var providerObj + $.ajax({ + url: createURL("listTungstenProviders"), + async: false, + success: function (json) { + providerObj = json.listTungstenProviders.tungstenProvider + } + }); + args.response.success({ + data: providerObj + }); + }, + detailView: { + name: "Tungsten Provider", + tabs: { + details: { + title: 'label.tungsten.providerdetail', + fields:[ { + name: { + label: 'label.name' + }, + tungstenproviderhostname: { + label: 'label.tungsten.provider.hostname', header: true + }, + tungstenproviderport: { + label: 'label.tungsten.provider.port' + } + }], + dataProvider: function (args) { + var providerObj + $.ajax({ + url: createURL("listTungstenProviders&tungstenprovideruuid=" + args.jsonObj.uuid), + dataType: "json", + async: false, + success: function (json) { + providerObj = json.listTungstenProviders.tungstenProvider + } + }); + args.response.success({ + data: providerObj[0], + actionFilter: function(args) { return [ 'remove' ] } + }); + } + } + }, + actions: { + remove: { + label: 'label.tungsten.delete.provider', + action: function (args) { + $.ajax({ + url: createURL("deleteTungstenProvider&tungstenprovideruuid=" + args.context.tungstenProviderList[0].uuid), + dataType: "json", + async: true, + success: function (json) { + args.response.success({ + _custom: { + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + } + ); + } + }); + }, + messages: { + confirm: function(args) { + return 'message.action.delete.provider'; + }, + notification: function(args) { + return 'label.tungsten.delete.provider' + } + }, + notification: { + poll: function(args) { + args.complete(); + $(window).trigger('cloudStack.fullRefresh'); + } + } + } + } + } + } + } + }, + actions: { + add: { + label: 'label.tungsten.add.provider', + createForm: { + title: 'label.tungsten.add.provider', + fields: { + name: { + label: 'label.name', + validation: { + required: true + } + }, + hostname: { + label: 'label.tungsten.provider.hostname', + validation: { + required: true + } + }, + port: { + label: 'label.tungsten.provider.port', + validation: { + required: true + } + } + } + }, + action: function (args) { + addTungstenProvider(args); + }, + messages: { + notification: function (args) { + return 'label.tungsten.add.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + enable: { + label: 'label.enable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "Tungsten"].id + "&state=Enabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.enable.provider'; + }, + notification: function () { + return 'label.enable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult + } + }, + disable: { + label: 'label.disable.provider', + action: function (args) { + $.ajax({ + url: createURL("updateNetworkServiceProvider&id=" + nspMap[ "Tungsten"].id + "&state=Disabled"), + dataType: "json", + success: function (json) { + var jid = json.updatenetworkserviceproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + $(window).trigger('cloudStack.fullRefresh'); + } + } + }); + } + }); + }, + messages: { + confirm: function (args) { + return 'message.confirm.disable.provider'; + }, + notification: function () { + return 'label.disable.provider'; + } + }, + notification: { + poll: pollAsyncJobResult } } } @@ -21816,6 +22003,34 @@ } } + function addTungstenProvider(args) { + $.ajax({ + url: createURL('createTungstenProvider'), + data: { + nspid: nspMap[ "Tungsten"].id, + tungstenproviderhostname: args.data.hostname, + name: args.data.name, + tungstenproviderport: args.data.port + }, + type: "POST", + success: function (json) { + var jid = json.createtungstenproviderresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function (json) { + var item = json.queryasyncjobresultresponse.jobresult.tungstenProvider; + return item; + } + } + }); + }, + error: function(json) { + args.response.error(parseXMLHttpResponse(json)); + } + }); + } + // Inject cloudStack infra page cloudStack.sections.system.show = cloudStack.uiCustom.physicalResources(cloudStack.sections.system.physicalResourceSection); From 2ce790a87bbfb6dff2ef551fe69ff6bcf760e784 Mon Sep 17 00:00:00 2001 From: Huy Le Date: Tue, 8 Sep 2020 13:35:33 +0700 Subject: [PATCH 08/62] Integrate tungsten virtual router with cloudstack --- .../main/java/com/cloud/network/Networks.java | 3 +- .../network/guru/NetworkGuruTungsten.java | 14 - .../orchestration/NetworkOrchestrator.java | 10 - .../network/dao/TungstenProviderDaoImpl.java | 4 + .../network/element/TungstenProviderVO.java | 26 +- .../META-INF/db/schema-41400to41500.sql | 3 +- .../kvm/resource/VRouterVifDriver.java | 118 +- .../kvm/resource/LibvirtVifDriverTest.java | 4 +- .../command/CreateTungstenProviderCmd.java | 14 + .../response/TungstenProviderResponse.java | 24 + .../tungsten/service/TungstenElement.java | 11 +- .../service/TungstenGuestNetworkGuru.java | 224 ++- .../tungsten/service/TungstenManagerImpl.java | 2 +- .../service/TungstenProviderServiceImpl.java | 2 +- .../service/TungstenResponseHelper.java | 2 + .../tungsten/service/TungstenService.java | 47 +- .../tungsten/service/TungstenServiceImpl.java | 238 ++- .../network/tungsten/vrouter/Port.java | 11 + ui/l10n/en.js | 2 + ui/scripts/system.js | 28 +- ui/scripts/ui-custom/zoneWizard.js | 1437 +++++++++++++++++ .../java/com/cloud/utils/TungstenUtils.java | 26 + 22 files changed, 1997 insertions(+), 253 deletions(-) delete mode 100644 api/src/main/java/com/cloud/network/guru/NetworkGuruTungsten.java create mode 100644 ui/scripts/ui-custom/zoneWizard.js create mode 100644 utils/src/main/java/com/cloud/utils/TungstenUtils.java diff --git a/api/src/main/java/com/cloud/network/Networks.java b/api/src/main/java/com/cloud/network/Networks.java index f892e253b359..ee8beb747a2c 100644 --- a/api/src/main/java/com/cloud/network/Networks.java +++ b/api/src/main/java/com/cloud/network/Networks.java @@ -127,7 +127,8 @@ public URI toUri(T value) { } }, UnDecided(null, null), - OpenDaylight("opendaylight", String.class); + OpenDaylight("opendaylight", String.class), + Tungsten("tf", String.class); private final String scheme; private final Class type; diff --git a/api/src/main/java/com/cloud/network/guru/NetworkGuruTungsten.java b/api/src/main/java/com/cloud/network/guru/NetworkGuruTungsten.java deleted file mode 100644 index d678308e0484..000000000000 --- a/api/src/main/java/com/cloud/network/guru/NetworkGuruTungsten.java +++ /dev/null @@ -1,14 +0,0 @@ -package com.cloud.network.guru; - -import com.cloud.network.Network; -import com.cloud.user.Account; - -import java.io.IOException; -import java.util.List; - -public interface NetworkGuruTungsten { - void createNetworkInTungsten(Network networkVO, Account owner) throws IOException; - String createVirtualMachineInTungsten(String virtualMachineUuid, String virtualMachineName); - String createVmInterfaceInTungsten(String vmInterfaceName, String tungstenProjectUuid, String tungstenNetworkUuid, String tungstenVirtualMachineUuid, String tungstenSecurityGroupUuid, List tungstenVmInterfaceMacAddresses); - void createTungstenInstanceIp(String instanceIpName, String tungstenVmInterfaceUuid, String tungstenNetworkUuid, String tungstenInstanceIpAddress); -} diff --git a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java index c77d89c29726..4a777cfcafef 100644 --- a/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java +++ b/engine/orchestration/src/main/java/org/apache/cloudstack/engine/orchestration/NetworkOrchestrator.java @@ -117,7 +117,6 @@ import com.cloud.network.element.VirtualRouterElement; import com.cloud.network.guru.NetworkGuru; import com.cloud.network.guru.NetworkGuruAdditionalFunctions; -import com.cloud.network.guru.NetworkGuruTungsten; import com.cloud.network.lb.LoadBalancingRulesManager; import com.cloud.network.router.VirtualRouter; import com.cloud.network.rules.FirewallManager; @@ -211,7 +210,6 @@ import javax.inject.Inject; import javax.naming.ConfigurationException; -import java.io.IOException; import java.net.URI; import java.util.ArrayList; import java.util.Arrays; @@ -708,14 +706,6 @@ public void doInTransactionWithoutResult(final TransactionStatus status) { vo.setDisplayNetwork(isDisplayNetworkEnabled == null ? true : isDisplayNetworkEnabled); vo.setStrechedL2Network(offering.isSupportingStrechedL2()); - if(guru instanceof NetworkGuruTungsten){ - try { - ((NetworkGuruTungsten) guru).createNetworkInTungsten(vo, owner); - } catch (IOException e) { - throw new CloudRuntimeException("Unable to create a network in tungsten"); - } - } - final NetworkVO networkPersisted = _networksDao.persist(vo, vo.getGuestType() == Network.GuestType.Isolated, finalizeServicesAndProvidersForNetwork(offering, plan.getPhysicalNetworkId())); networks.add(networkPersisted); diff --git a/engine/schema/src/main/java/com/cloud/network/dao/TungstenProviderDaoImpl.java b/engine/schema/src/main/java/com/cloud/network/dao/TungstenProviderDaoImpl.java index 57612e900acc..752ac832a98e 100644 --- a/engine/schema/src/main/java/com/cloud/network/dao/TungstenProviderDaoImpl.java +++ b/engine/schema/src/main/java/com/cloud/network/dao/TungstenProviderDaoImpl.java @@ -27,6 +27,10 @@ public TungstenProviderDaoImpl() { SearchCriteria.Op.EQ); AllFieldsSearch.and("port", AllFieldsSearch.entity().getPort(), SearchCriteria.Op.EQ); + AllFieldsSearch.and("vrouter", AllFieldsSearch.entity().getVrouter(), + SearchCriteria.Op.EQ); + AllFieldsSearch.and("vrouter_port", AllFieldsSearch.entity().getVrouterPort(), + SearchCriteria.Op.EQ); AllFieldsSearch.done(); } diff --git a/engine/schema/src/main/java/com/cloud/network/element/TungstenProviderVO.java b/engine/schema/src/main/java/com/cloud/network/element/TungstenProviderVO.java index a93b83659418..3e954ebb82ab 100644 --- a/engine/schema/src/main/java/com/cloud/network/element/TungstenProviderVO.java +++ b/engine/schema/src/main/java/com/cloud/network/element/TungstenProviderVO.java @@ -34,16 +34,24 @@ public class TungstenProviderVO implements TungstenProvider { @Column(name = "hostname") private String hostname; + @Column(name = "vrouter") + private String vrouter; + + @Column(name = "vrouter_port") + private String vrouterPort; + public TungstenProviderVO() { this.uuid = UUID.randomUUID().toString(); } - public TungstenProviderVO(long nspId, String providerName, String port, String hostname) { + public TungstenProviderVO(long nspId, String providerName, String port, String hostname, String vrouter, String vrouterPort) { this.nspId = nspId; this.uuid = UUID.randomUUID().toString(); this.providerName = providerName; this.port = port; this.hostname = hostname; + this.vrouter = vrouter; + this.vrouterPort = vrouterPort; } @Override @@ -95,4 +103,20 @@ public long getNspId() { public void setNspId(long nspId) { this.nspId = nspId; } + + public String getVrouter() { + return vrouter; + } + + public void setVrouter(final String vrouter) { + this.vrouter = vrouter; + } + + public String getVrouterPort() { + return vrouterPort; + } + + public void setVrouterPort(final String vrouterPort) { + this.vrouterPort = vrouterPort; + } } diff --git a/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql b/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql index 5603ee4029db..a717a2758311 100644 --- a/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql +++ b/engine/schema/src/main/resources/META-INF/db/schema-41400to41500.sql @@ -19,7 +19,6 @@ -- Schema upgrade from 4.14.0.0 to 4.15.0.0 --; ALTER TABLE `cloud`.`network_offerings` ADD COLUMN `for_tungsten` int(1) unsigned DEFAULT '0' COMMENT 'is tungsten enabled for the resource'; -ALTER TABLE `cloud`.`networks` ADD COLUMN `tungsten_network_uuid` varchar(255) COMMENT 'tungsten id'; -- Network offering with multi-domains and multi-zones DROP VIEW IF EXISTS `cloud`.`network_offering_view`; @@ -93,6 +92,8 @@ CREATE TABLE `cloud`.`tungsten_providers` ( `provider_name` varchar(40), `port` varchar(40), `hostname` varchar(40), + `vrouter` varchar(40), + `vrouter_port` varchar(40), PRIMARY KEY (`id`), CONSTRAINT `fk_tungsten_providers__nsp_id` FOREIGN KEY (`nsp_id`) REFERENCES `physical_network_service_providers` (`id`) ON DELETE CASCADE, CONSTRAINT `uc_tungsten_providers__uuid` UNIQUE (`uuid`) diff --git a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/VRouterVifDriver.java b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/VRouterVifDriver.java index 1fb0fca20188..2a15ad90fd04 100644 --- a/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/VRouterVifDriver.java +++ b/plugins/hypervisors/kvm/src/main/java/com/cloud/hypervisor/kvm/resource/VRouterVifDriver.java @@ -3,6 +3,7 @@ import com.cloud.agent.api.to.NicTO; import com.cloud.exception.InternalErrorException; import com.cloud.utils.NumbersUtil; +import com.cloud.utils.TungstenUtils; import com.cloud.utils.script.Script; import org.apache.log4j.Logger; import org.libvirt.LibvirtException; @@ -12,84 +13,83 @@ import javax.naming.ConfigurationException; public class VRouterVifDriver extends VifDriverBase { - private static final Logger s_logger = Logger.getLogger(VRouterVifDriver.class); - private int _timeout; - private String _createTapDeviceScript; - private String _deleteTapDeviceScript; + private static final Logger s_logger = Logger.getLogger(VRouterVifDriver.class); + private int _timeout; + private String _createTapDeviceScript; + private String _deleteTapDeviceScript; - @Override - public void configure(final Map params) throws ConfigurationException { - super.configure(params); + @Override + public void configure(final Map params) throws ConfigurationException { - String tungstenScriptsDir = (String) params.get("tungsten.scripts.dir"); - tungstenScriptsDir = - tungstenScriptsDir == null ? "scripts/vm/network/tungsten" : tungstenScriptsDir; + super.configure(params); - final String value = (String) params.get("scripts.timeout"); - _timeout = NumbersUtil.parseInt(value, 30 * 60) * 1000; + String tungstenScriptsDir = (String) params.get("tungsten.scripts.dir"); + tungstenScriptsDir = tungstenScriptsDir == null ? "scripts/vm/network/tungsten" : tungstenScriptsDir; - _createTapDeviceScript = Script.findScript(tungstenScriptsDir, "create_tap_device.sh"); - _deleteTapDeviceScript = Script.findScript(tungstenScriptsDir, "delete_tap_device.sh"); + final String value = (String) params.get("scripts.timeout"); + _timeout = NumbersUtil.parseInt(value, 30 * 60) * 1000; - if (_createTapDeviceScript == null) { - throw new ConfigurationException("Unable to find create_tap_device.sh"); - } + _createTapDeviceScript = Script.findScript(tungstenScriptsDir, "create_tap_device.sh"); + _deleteTapDeviceScript = Script.findScript(tungstenScriptsDir, "delete_tap_device.sh"); + + if (_createTapDeviceScript == null) { + throw new ConfigurationException("Unable to find create_tap_device.sh"); + } - if (_deleteTapDeviceScript == null) { - throw new ConfigurationException("Unable to find delete_tap_device.sh"); + if (_deleteTapDeviceScript == null) { + throw new ConfigurationException("Unable to find delete_tap_device.sh"); + } } - } - @Override - public LibvirtVMDef.InterfaceDef plug(final NicTO nic, final String guestOsType, - final String nicAdapter, final Map extraConfig) - throws InternalErrorException, LibvirtException { + @Override + public LibvirtVMDef.InterfaceDef plug(final NicTO nic, final String guestOsType, final String nicAdapter, + final Map extraConfig) throws InternalErrorException, LibvirtException { - final String tapDeviceName = getTapName(nic.getMac()); - final String script = _createTapDeviceScript; + final String tapDeviceName = TungstenUtils.getTapName(nic.getMac()); + final String script = _createTapDeviceScript; - final Script command = new Script(script, _timeout, s_logger); - command.add("name", tapDeviceName); + final Script command = new Script(script, _timeout, s_logger); + command.add(tapDeviceName); - final String result = command.execute(); - if (result != null) { - throw new InternalErrorException( - "Failed to create tap device " + tapDeviceName + ": " + result); - } + final String result = command.execute(); + if (result != null) { + throw new InternalErrorException("Failed to create tap device " + tapDeviceName + ": " + result); + } - final LibvirtVMDef.InterfaceDef intf = new LibvirtVMDef.InterfaceDef(); - intf.defEthernet(tapDeviceName, nic.getMac(), getGuestNicModel(guestOsType, nicAdapter)); + final LibvirtVMDef.InterfaceDef intf = new LibvirtVMDef.InterfaceDef(); + intf.defEthernet(tapDeviceName, nic.getMac(), getGuestNicModel(guestOsType, nicAdapter)); - return intf; - } + return intf; + } - @Override - public void unplug(final LibvirtVMDef.InterfaceDef iface) { - final String tapDeviceName = getTapName(iface.getMacAddress()); - final String script = _createTapDeviceScript; + @Override + public void unplug(final LibvirtVMDef.InterfaceDef iface) { + final String tapDeviceName = TungstenUtils.getTapName(iface.getMacAddress()); + final String script = _deleteTapDeviceScript; - final Script command = new Script(script, _timeout, s_logger); - command.add("name", tapDeviceName); + final Script command = new Script(script, _timeout, s_logger); + command.add(tapDeviceName); - final String result = command.execute(); - if (result != null) { - s_logger.error("Failed to delete tap device " + tapDeviceName + ": " + result); + final String result = command.execute(); + if (result != null) { + s_logger.error("Failed to delete tap device " + tapDeviceName + ": " + result); + } } - } - @Override - public void attach(final LibvirtVMDef.InterfaceDef iface) { - } + @Override + public void attach(final LibvirtVMDef.InterfaceDef iface) { + } - @Override - public void detach(final LibvirtVMDef.InterfaceDef iface) { - } + @Override + public void detach(final LibvirtVMDef.InterfaceDef iface) { + } - @Override - public void createControlNetwork(final String privBrName) { - } + @Override + public void createControlNetwork(final String privBrName) { + } - private String getTapName(final String macAddress) { - return "tap" + macAddress.replaceAll(":", ""); - } + @Override + public boolean isExistingBridge(String bridgeName) { + return bridgeName != null ? TungstenUtils.isTungstenBridge(bridgeName) : false; + } } diff --git a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVifDriverTest.java b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVifDriverTest.java index 098352915a84..870ab34a30a3 100644 --- a/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVifDriverTest.java +++ b/plugins/hypervisors/kvm/src/test/java/com/cloud/hypervisor/kvm/resource/LibvirtVifDriverTest.java @@ -54,7 +54,7 @@ public class LibvirtVifDriverTest { final String FakeVifDriverClassName = "com.cloud.hypervisor.kvm.resource.FakeVifDriver"; final String NonExistentVifDriverClassName = "com.cloud.hypervisor.kvm.resource.NonExistentVifDriver"; - private VifDriver fakeVifDriver, bridgeVifDriver, ovsVifDriver; + private VifDriver fakeVifDriver, bridgeVifDriver, ovsVifDriver, tungstenVifDriver; final String memInfo = "MemTotal: 5830236 kB\n" + "MemFree: 156752 kB\n" + @@ -74,6 +74,7 @@ public void setUp() throws Exception { try { bridgeVifDriver = (VifDriver)Class.forName(LibvirtComputingResource.DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME).newInstance(); ovsVifDriver = (VifDriver)Class.forName(LibvirtComputingResource.DEFAULT_OVS_VIF_DRIVER_CLASS_NAME).newInstance(); + tungstenVifDriver = (VifDriver)Class.forName(LibvirtComputingResource.DEFAULT_TUNGSTEN_VIF_DRIVER_CLASS_NAME).newInstance(); // Instantiating bridge vif driver again as the fake vif driver // is good enough, as this is a separate instance @@ -81,6 +82,7 @@ public void setUp() throws Exception { doReturn(bridgeVifDriver).when(res).getVifDriverClass(eq(LibvirtComputingResource.DEFAULT_BRIDGE_VIF_DRIVER_CLASS_NAME), anyMap()); doReturn(ovsVifDriver).when(res).getVifDriverClass(eq(LibvirtComputingResource.DEFAULT_OVS_VIF_DRIVER_CLASS_NAME), anyMap()); + doReturn(tungstenVifDriver).when(res).getVifDriverClass(eq(LibvirtComputingResource.DEFAULT_TUNGSTEN_VIF_DRIVER_CLASS_NAME), anyMap()); doReturn(fakeVifDriver).when(res).getVifDriverClass(eq(FakeVifDriverClassName), anyMap()); } catch (final ConfigurationException ex) { diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenProviderCmd.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenProviderCmd.java index 5e4151ea851b..abc28dc89081 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenProviderCmd.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/command/CreateTungstenProviderCmd.java @@ -57,6 +57,12 @@ public class CreateTungstenProviderCmd extends BaseAsyncCreateCmd { @Parameter(name = ApiConstants.TUNGSTEN_PROVIDER_PORT, type = CommandType.STRING, required = true, description = "Tungsten provider port") private String port; + @Parameter(name = ApiConstants.TUNGSTEN_PROVIDER_VROUTER, type = CommandType.STRING, required = true, description = "Tungsten provider vrouter") + private String vrouter; + + @Parameter(name = ApiConstants.TUNGSTEN_PROVIDER_VROUTER_PORT, type = CommandType.STRING, required = true, description = "Tungsten provider vrouter port") + private String vrouterPort; + public Long getNspId() { return nspId; } @@ -73,6 +79,14 @@ public String getPort() { return port; } + public String getVrouter() { + return vrouter; + } + + public String getVrouterPort() { + return vrouterPort; + } + @Inject private TungstenProviderService tungstenProviderService; diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenProviderResponse.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenProviderResponse.java index e65c4eafe66f..02045024798a 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenProviderResponse.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/api/response/TungstenProviderResponse.java @@ -26,6 +26,14 @@ public class TungstenProviderResponse extends BaseResponse { @Param(description = "tungsten provider port") private String port; + @SerializedName(ApiConstants.TUNGSTEN_PROVIDER_VROUTER) + @Param(description = "tungsten provider port") + private String vrouter; + + @SerializedName(ApiConstants.TUNGSTEN_PROVIDER_VROUTER_PORT) + @Param(description = "tungsten provider port") + private String vrouterPort; + public String getHostname() { return hostname; } @@ -57,4 +65,20 @@ public String getUuid() { public void setUuid(String uuid) { this.uuid = uuid; } + + public String getVrouter() { + return vrouter; + } + + public void setVrouter(final String vrouter) { + this.vrouter = vrouter; + } + + public String getVrouterPort() { + return vrouterPort; + } + + public void setVrouterPort(final String vrouterPort) { + this.vrouterPort = vrouterPort; + } } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java index 67a05512eb91..0651fe4aaef3 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenElement.java @@ -64,10 +64,17 @@ public Map> getCapabilities() { private static Map> InitCapabilities() { Map> capabilities = new HashMap>(); - capabilities.put(Network.Service.Dhcp, new HashMap()); - Map sourceNatCapabilities = new HashMap(); + final Map dhcpCapabilities = new HashMap<>(); + capabilities.put(Network.Service.Dhcp, dhcpCapabilities); + Map sourceNatCapabilities = new HashMap<>(); + sourceNatCapabilities.put(Network.Capability.RedundantRouter, "true"); sourceNatCapabilities.put(Network.Capability.SupportedSourceNatTypes, "peraccount"); capabilities.put(Network.Service.SourceNat, sourceNatCapabilities); + capabilities.put(Network.Service.Connectivity, null); + capabilities.put(Network.Service.StaticNat, null); + final Map dnsCapabilities = new HashMap<>(); + dnsCapabilities.put(Network.Capability.AllowDnsSuffixModification, "true"); + capabilities.put(Network.Service.Dns, dnsCapabilities); return capabilities; } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java index 7f382f1f68cb..f9896e0f3959 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenGuestNetworkGuru.java @@ -11,39 +11,70 @@ import com.cloud.network.dao.NetworkVO; import com.cloud.network.dao.PhysicalNetworkVO; import com.cloud.network.guru.GuestNetworkGuru; -import com.cloud.network.guru.NetworkGuruTungsten; import com.cloud.offering.NetworkOffering; +import com.cloud.offerings.dao.NetworkOfferingServiceMapDao; import com.cloud.user.Account; +import com.cloud.utils.TungstenUtils; import com.cloud.utils.db.DB; import com.cloud.utils.exception.CloudRuntimeException; import com.cloud.vm.Nic; import com.cloud.vm.NicProfile; import com.cloud.vm.ReservationContext; import com.cloud.vm.VirtualMachineProfile; +import net.juniper.contrail.api.ApiPropertyBase; +import net.juniper.contrail.api.ObjectReference; +import net.juniper.contrail.api.types.InstanceIp; +import net.juniper.contrail.api.types.NetworkIpam; import net.juniper.contrail.api.types.Project; import net.juniper.contrail.api.types.VirtualMachine; import net.juniper.contrail.api.types.VirtualMachineInterface; import net.juniper.contrail.api.types.VirtualNetwork; +import net.juniper.contrail.api.types.VnSubnetsType; +import org.apache.cloudstack.network.tungsten.vrouter.Port; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import javax.inject.Inject; import java.io.IOException; -import java.util.Arrays; import java.util.List; +import javax.inject.Inject; + @Component -public class TungstenGuestNetworkGuru extends GuestNetworkGuru implements NetworkGuruTungsten { +public class TungstenGuestNetworkGuru extends GuestNetworkGuru { - private static final Logger s_logger = Logger - .getLogger(TungstenGuestNetworkGuru.class); + private static final Logger s_logger = Logger.getLogger(TungstenGuestNetworkGuru.class); @Inject TungstenService tungstenService; + @Inject + protected NetworkOfferingServiceMapDao ntwkOfferingSrvcDao; + + private static final Networks.TrafficType[] TrafficTypes = {Networks.TrafficType.Guest}; + + public TungstenGuestNetworkGuru() { + _isolationMethods = new PhysicalNetwork.IsolationMethod[] {new PhysicalNetwork.IsolationMethod("TF")}; + } @Override - protected boolean canHandle(NetworkOffering offering, DataCenter.NetworkType networkType, PhysicalNetwork physicalNetwork) { - return offering.isForTungsten(); + public boolean isMyTrafficType(Networks.TrafficType type) { + for (Networks.TrafficType t : TrafficTypes) { + if (t == type) { + return true; + } + } + return false; + } + + @Override + protected boolean canHandle(NetworkOffering offering, DataCenter.NetworkType networkType, + PhysicalNetwork physicalNetwork) { + if (networkType == DataCenter.NetworkType.Advanced && isMyTrafficType(offering.getTrafficType()) + && offering.getGuestType() == Network.GuestType.Isolated && isMyIsolationMethod(physicalNetwork) + && ntwkOfferingSrvcDao.isProviderForNetworkOffering(offering.getId(), Network.Provider.Tungsten)) { + return true; + } + + return false; } @Override @@ -59,14 +90,20 @@ public Network design(NetworkOffering offering, DeploymentPlan plan, Network use NetworkVO network = (NetworkVO) super.design(offering, plan, userSpecified, owner); + if (network == null) { + return null; + } + + network.setBroadcastDomainType(Networks.BroadcastDomainType.Tungsten); return network; } @Override - public NicProfile allocate(Network config, NicProfile nic, VirtualMachineProfile vm) throws InsufficientVirtualNetworkCapacityException, - InsufficientAddressCapacityException { + public NicProfile allocate(Network config, NicProfile nic, VirtualMachineProfile vm) + throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { - if (_networkModel.networkIsConfiguredForExternalNetworking(config.getDataCenterId(), config.getId()) && nic != null && nic.getRequestedIPv4() != null) { + if (_networkModel.networkIsConfiguredForExternalNetworking(config.getDataCenterId(), config.getId()) + && nic != null && nic.getRequestedIPv4() != null) { throw new CloudRuntimeException("Does not support custom ip allocation at this time: " + nic); } @@ -74,7 +111,8 @@ public NicProfile allocate(Network config, NicProfile nic, VirtualMachineProfile if (_networkModel.networkIsConfiguredForExternalNetworking(config.getDataCenterId(), config.getId())) { profile.setReservationStrategy(Nic.ReservationStrategy.Start); - /* We won't clear IP address, because router may set gateway as it IP, and it would be updated properly later */ + /* We won't clear IP address, because router may set gateway as it IP, and it would be updated properly + later */ //profile.setIp4Address(null); profile.setIPv4Gateway(null); profile.setIPv4Netmask(null); @@ -96,37 +134,28 @@ public void deallocate(Network config, NicProfile nic, VirtualMachineProfile vm) nic.setIsolationUri(null); } try { - tungstenService.expugeVmFromTungsten(vm.getUuid()); + tungstenService.deleteObject(VirtualMachine.class, vm.getUuid()); } catch (IOException e) { throw new CloudRuntimeException("Failing to expuge the vm from tungsten with the uuid " + vm.getUuid()); } } @Override - public Network implement(Network network, NetworkOffering offering, DeployDestination dest, ReservationContext context) throws InsufficientVirtualNetworkCapacityException { + public Network implement(Network network, NetworkOffering offering, DeployDestination dest, + ReservationContext context) throws InsufficientVirtualNetworkCapacityException { - assert (network.getState() == Network.State.Implementing) : "Why are we implementing " - + network; + assert (network.getState() == Network.State.Implementing) : "Why are we implementing " + network; long dcId = dest.getDataCenter().getId(); - DataCenter.NetworkType nwType = dest.getDataCenter().getNetworkType(); + // get physical network id Long physicalNetworkId = network.getPhysicalNetworkId(); - // physical network id can be null in Guest Network in Basic zone, so - // locate the physical network - if (physicalNetworkId == null) { - physicalNetworkId = _networkModel.findPhysicalNetworkId(dcId, - offering.getTags(), offering.getTrafficType()); - } - PhysicalNetworkVO physnet = _physicalNetworkDao - .findById(physicalNetworkId); - if (!canHandle(offering, nwType, physnet)) { - s_logger.debug("Refusing to implement this network"); - return null; - } - NetworkVO implemented = (NetworkVO) super.implement(network, offering, - dest, context); + PhysicalNetworkVO physnet = _physicalNetworkDao.findById(physicalNetworkId); + + NetworkVO implemented = new NetworkVO(network.getTrafficType(), network.getMode(), + network.getBroadcastDomainType(), network.getNetworkOfferingId(), Network.State.Allocated, + network.getDataCenterId(), physicalNetworkId, offering.isRedundantRouter()); if (network.getGateway() != null) { implemented.setGateway(network.getGateway()); @@ -136,24 +165,111 @@ public Network implement(Network network, NetworkOffering offering, DeployDestin implemented.setCidr(network.getCidr()); } - implemented.setBroadcastDomainType(Networks.BroadcastDomainType.Vxlan); + implemented.setBroadcastUri(Networks.BroadcastDomainType.Tungsten.toUri("tf")); + + // setup tungsten network + try { + VirtualNetwork virtualNetwork = tungstenService.getVirtualNetworkFromTungsten(network.getUuid()); + if (virtualNetwork == null) { + Project project = tungstenService.getTungstenNetworkProject(context.getAccount()); + + // we use default network ipam + NetworkIpam networkIpam = tungstenService.getDefaultProjectNetworkIpam(project); + + // create tungsten subnet + DataCenter dataCenter = _dcDao.findById(network.getDataCenterId()); + + String cidr = network.getCidr(); + if (cidr == null) { + cidr = dataCenter.getGuestNetworkCidr(); + } + String[] addr_pair = cidr.split("\\/"); + String gateway = network.getGateway(); + boolean isDhcpEnable = network.getMode().equals(Networks.Mode.Dhcp); + + VnSubnetsType subnet = tungstenService.getVnSubnetsType(null, null, addr_pair[0], + Integer.parseInt(addr_pair[1]), gateway, isDhcpEnable, null, true); + + tungstenService.createTungstenVirtualNetwork(network, project, networkIpam, subnet); + } + + } catch (Exception ex) { + throw new CloudRuntimeException("unable to create tungsten network " + network.getUuid()); + } return implemented; } @Override - public void reserve(final NicProfile nic, final Network network, final VirtualMachineProfile vm, final DeployDestination dest, final ReservationContext context) - throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { + public void reserve(final NicProfile nic, final Network network, final VirtualMachineProfile vm, + final DeployDestination dest, final ReservationContext context) + throws InsufficientVirtualNetworkCapacityException, InsufficientAddressCapacityException { super.reserve(nic, network, vm, dest, context); + + // create tungsten vm, vmi, instance ip + VirtualMachine virtualMachine; + VirtualMachineInterface virtualMachineInterface; + InstanceIp instanceIp; + VirtualNetwork virtualNetwork; try { - String tungstenVirtualMachineUuid = createVirtualMachineInTungsten(vm.getUuid(), vm.getInstanceName()); - Project project = tungstenService.getTungstenNetworkProject(vm.getOwner()); - String tungstenVmInterfaceUuid = createVmInterfaceInTungsten(vm.getInstanceName(), project.getUuid(), - network.getUuid(), tungstenVirtualMachineUuid, null, Arrays.asList(nic.getMacAddress())); - createTungstenInstanceIp(vm.getInstanceName() + "-InstanceIp", tungstenVmInterfaceUuid, network.getUuid(), nic.getIPv4Address()); + // for sure tungsten network is created + virtualNetwork = tungstenService.getVirtualNetworkFromTungsten(network.getUuid()); + if (virtualNetwork == null) { + throw new CloudRuntimeException("Tungsten network " + network.getUuid() + " is unavailable"); + } + + Project project = tungstenService.getTungstenNetworkProject(context.getAccount()); + + virtualMachine = (VirtualMachine) tungstenService.getObject(VirtualMachine.class, vm.getUuid()); + if (virtualMachine == null) { + virtualMachine = tungstenService.createVmInTungsten(vm.getUuid(), vm.getInstanceName()); + } + + virtualMachineInterface = (VirtualMachineInterface) tungstenService.getObject(VirtualMachineInterface.class, + nic.getUuid()); + if (virtualMachineInterface == null) { + virtualMachineInterface = tungstenService.createVmInterfaceInTungsten(nic, virtualNetwork, + virtualMachine, project); + } + + instanceIp = tungstenService.createInstanceIpInTungsten(virtualNetwork, virtualMachineInterface, + nic); + + Port port = new Port(); + port.setId(virtualMachineInterface.getUuid()); + port.setVnId(virtualNetwork.getUuid()); + port.setDisplayName(virtualMachine.getName()); + port.setVmProjectId(project.getUuid()); + port.setMacAddress(nic.getMacAddress()); + port.setIpAddress(instanceIp.getAddress()); + port.setInstanceId(virtualMachine.getUuid()); + tungstenService.addTungstenVrouterPort(port); + + nic.setName(nic.getName() + TungstenUtils.getBridgeName()); } catch (IOException e) { - throw new CloudRuntimeException("Failed to create resources in tungsten for the network with uuid: " + vm.getUuid()); + throw new CloudRuntimeException( + "Failed to create resources in tungsten for the network with uuid: " + vm.getUuid()); + } + } + + @Override + public boolean release(final NicProfile nic, final VirtualMachineProfile vm, final String reservationId) { + try { + // delete instance ip and vmi + VirtualMachineInterface vmi = (VirtualMachineInterface) tungstenService.getObject( + VirtualMachineInterface.class, nic.getUuid()); + if (vmi != null) { + List> instanceIpORs = vmi.getInstanceIpBackRefs(); + for (ObjectReference instanceIpOR : instanceIpORs) { + tungstenService.deleteObject(InstanceIp.class, instanceIpOR.getUuid()); + } + tungstenService.deleteObject(VirtualMachineInterface.class, vmi.getUuid()); + tungstenService.deleteTungstenVrouterPort(vmi.getUuid()); + } + } catch (IOException ex) { + return false; } + return super.release(nic, vm, reservationId); } @Override @@ -165,32 +281,4 @@ public boolean trash(Network network, NetworkOffering offering) { } return super.trash(network, offering); } - - @Override - public void createNetworkInTungsten(Network networkVO, Account owner) throws IOException { - Project project = tungstenService.getTungstenNetworkProject(owner); - List subnetIp = Arrays.asList(networkVO.getCidr().split("/")); - String subnetIpPrefix = subnetIp.get(0); - int subnetIpPrefixLength = Integer.parseInt(subnetIp.get(1)); - boolean isDhcpEnabled = networkVO.getMode().equals(Networks.Mode.Dhcp); - VirtualNetwork virtualNetwork = tungstenService.createNetworkInTungsten(networkVO.getUuid(), networkVO.getName(), project.getUuid(), null, - null, null, subnetIpPrefix, subnetIpPrefixLength, networkVO.getGateway(), isDhcpEnabled, null, false); - } - - @Override - public String createVirtualMachineInTungsten(String virtualMachineUuid, String virtualMachineName) { - VirtualMachine virtualMachine = tungstenService.createVmInTungsten(virtualMachineUuid, virtualMachineName); - return virtualMachine.getUuid(); - } - - @Override - public String createVmInterfaceInTungsten(String vmInterfaceName, String tungstenProjectUuid, String tungstenNetworkUuid, String tungstenVirtualMachineUuid, String tungstenSecurityGroupUuid, List tungstenVmInterfaceMacAddresses) { - VirtualMachineInterface virtualMachineInterface = tungstenService.createVmInterfaceInTungsten(vmInterfaceName + "-Interface", tungstenProjectUuid, tungstenNetworkUuid, tungstenVirtualMachineUuid, tungstenSecurityGroupUuid, tungstenVmInterfaceMacAddresses); - return virtualMachineInterface.getUuid(); - } - - @Override - public void createTungstenInstanceIp(String instanceIpName, String tungstenVmInterfaceUuid, String tungstenNetworkUuid, String tungstenInstanceIpAddress) { - tungstenService.createInstanceIpInTungsten(instanceIpName, tungstenVmInterfaceUuid, tungstenNetworkUuid, tungstenInstanceIpAddress); - } } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java index 3f9966c5b3e2..7ce0402a71d4 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenManagerImpl.java @@ -163,7 +163,7 @@ public InstanceIp createInstanceIp(CreateTungstenInstanceIpCmd cmd) { @Override public VirtualMachineInterface createTungstenVirtualMachineInterface(CreateTungstenVmInterfaceCmd cmd) { - return tungstenService.createVmInterfaceInTungsten(cmd.getName(), cmd.getTungstenProjectUuid(), cmd.getTungstenNetworkUuid(), + return tungstenService.createVmInterfaceInTungsten(null, cmd.getName(), cmd.getTungstenProjectUuid(), cmd.getTungstenNetworkUuid(), cmd.getTungstenVirtualMachineUuid(), cmd.getTungstenSecurityGroupUuid(), cmd.getTungstenVmInterfaceMacAddresses()); } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderServiceImpl.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderServiceImpl.java index ce703634b886..7b95b9625846 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderServiceImpl.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenProviderServiceImpl.java @@ -46,7 +46,7 @@ public TungstenProvider addProvider(CreateTungstenProviderCmd cmd) throws Config s_logger.debug("There is already a tungsten provider with service network provider id " + cmd.getNspId()); return null; } - element = new TungstenProviderVO(cmd.getNspId(), cmd.getName(), cmd.getPort(), cmd.getHostname()); + element = new TungstenProviderVO(cmd.getNspId(), cmd.getName(), cmd.getPort(), cmd.getHostname(), cmd.getVrouter(), cmd.getVrouterPort()); _tungstenProviderDao.persist(element); _tungstenService.init(); return element; diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java index 4a07197a39f6..b83abc3ca20d 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenResponseHelper.java @@ -84,6 +84,8 @@ public static TungstenProviderResponse createTungstenProviderResponse(TungstenPr tungstenProviderResponse.setName(tungstenProviderVO.getProviderName()); tungstenProviderResponse.setPort(tungstenProviderVO.getPort()); tungstenProviderResponse.setUuid(tungstenProviderVO.getUuid()); + tungstenProviderResponse.setVrouter(tungstenProviderVO.getVrouter()); + tungstenProviderResponse.setVrouterPort(tungstenProviderVO.getVrouterPort()); tungstenProviderResponse.setObjectName("tungstenProvider"); return tungstenProviderResponse; } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenService.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenService.java index d9f35b57b767..fa83bc6fd77e 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenService.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenService.java @@ -1,15 +1,20 @@ package org.apache.cloudstack.network.tungsten.service; +import com.cloud.network.Network; import com.cloud.user.Account; +import com.cloud.vm.NicProfile; import net.juniper.contrail.api.ApiConnector; +import net.juniper.contrail.api.ApiObjectBase; import net.juniper.contrail.api.types.InstanceIp; +import net.juniper.contrail.api.types.NetworkIpam; import net.juniper.contrail.api.types.Project; import net.juniper.contrail.api.types.VirtualMachine; import net.juniper.contrail.api.types.VirtualMachineInterface; import net.juniper.contrail.api.types.VirtualNetwork; +import net.juniper.contrail.api.types.VnSubnetsType; +import org.apache.cloudstack.network.tungsten.vrouter.Port; import org.apache.cloudstack.network.tungsten.vrouter.VRouterApiConnector; -import javax.naming.ConfigurationException; import java.io.IOException; import java.util.List; @@ -17,24 +22,27 @@ public interface TungstenService { public static final String TUNGSTEN_DEFAULT_DOMAIN = "default-domain"; public static final String TUNGSTEN_DEFAULT_PROJECT = "default-project"; + public static final String TUNGSTEN_DEFAULT_IPAM = "default-network-ipam"; - void init() throws ConfigurationException; + void init(); ApiConnector get_api(); VRouterApiConnector get_vrouterApi(); - VirtualNetwork createNetworkInTungsten(String networkUuid, String networkName, String projectUuid, String networkIpamUuid, String ipAllocPoolStart, - String ipAllocPoolEnd, String subnetIpPrefix, int subnetIpPrefixLength, String defaultGateway, - boolean isDhcpEnabled, List dnsNameservers, boolean isIpAddrFromStart); + VirtualNetwork createNetworkInTungsten(String networkUuid, String networkName, String projectUuid, + String networkIpamUuid, String ipAllocPoolStart, String ipAllocPoolEnd, String subnetIpPrefix, + int subnetIpPrefixLength, String defaultGateway, boolean isDhcpEnabled, List dnsNameservers, + boolean isIpAddrFromStart); VirtualMachine createVmInTungsten(String vmUuid, String vmName); - InstanceIp createInstanceIpInTungsten(String instanceIpName, String tungstenVmInterfaceUuid, String tungstenNetworkUuid, - String tungstenInstanceIpAddress); + InstanceIp createInstanceIpInTungsten(String instanceIpName, String tungstenVmInterfaceUuid, + String tungstenNetworkUuid, String tungstenInstanceIpAddress); - VirtualMachineInterface createVmInterfaceInTungsten(String vmInterfaceName, String tungstenProjectUuid, String tungstenNetworkUuid, - String tungstenVmUuid, String tungstenSecurityGroupUuid, List tungstenVmInterfaceMacAddresses); + VirtualMachineInterface createVmInterfaceInTungsten(String vmiUuid, String vmInterfaceName, + String tungstenProjectUuid, String tungstenNetworkUuid, String tungstenVmUuid, String tungstenSecurityGroupUuid, + List tungstenVmInterfaceMacAddresses); VirtualNetwork deleteNetworkFromTungsten(String tungstenNetworkUuid) throws IOException; @@ -44,4 +52,25 @@ VirtualMachineInterface createVmInterfaceInTungsten(String vmInterfaceName, Stri Project getTungstenNetworkProject(Account owner) throws IOException; + void addTungstenVrouterPort(Port port) throws IOException; + + void deleteTungstenVrouterPort(String portUuid) throws IOException; + + InstanceIp createInstanceIpInTungsten(VirtualNetwork vn, VirtualMachineInterface vmi, NicProfile nic); + + VirtualMachineInterface createVmInterfaceInTungsten(NicProfile nicProfile, VirtualNetwork vn, VirtualMachine vm, + Project project); + + ApiObjectBase getObject(Class obj, String uuid) throws IOException; + + NetworkIpam getDefaultProjectNetworkIpam(Project project) throws IOException; + + VnSubnetsType getVnSubnetsType(String ipAllocPoolStart, String ipAllocPoolEnd, String subnetIpPrefix, + int subnetIpPrefixLength, String defaultGateway, boolean isDhcpEnabled, List dnsNameservers, + boolean isIpAddrFromStart); + + VirtualNetwork createTungstenVirtualNetwork(Network network, Project project, NetworkIpam networkIpam, + VnSubnetsType subnet); + + void deleteObject(Class obj, String uuid) throws IOException; } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImpl.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImpl.java index f3d6f7838f6c..07665e9e270e 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImpl.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/service/TungstenServiceImpl.java @@ -2,13 +2,14 @@ import com.cloud.domain.DomainVO; import com.cloud.domain.dao.DomainDao; -import com.cloud.exception.InvalidParameterValueException; +import com.cloud.network.Network; import com.cloud.network.element.TungstenProviderVO; import com.cloud.projects.ProjectVO; import com.cloud.projects.dao.ProjectDao; import com.cloud.user.Account; import com.cloud.user.dao.AccountDao; -import com.cloud.utils.PropertiesUtil; +import com.cloud.utils.TungstenUtils; +import com.cloud.vm.NicProfile; import net.juniper.contrail.api.ApiConnector; import net.juniper.contrail.api.ApiConnectorFactory; import net.juniper.contrail.api.ApiObjectBase; @@ -27,23 +28,18 @@ import net.juniper.contrail.api.types.VnSubnetsType; import org.apache.cloudstack.api.ApiErrorCode; import org.apache.cloudstack.api.ServerApiException; +import org.apache.cloudstack.network.tungsten.vrouter.Port; import org.apache.cloudstack.network.tungsten.vrouter.VRouterApiConnector; import org.apache.cloudstack.network.tungsten.vrouter.VRouterApiConnectorFactory; -import org.apache.commons.io.IOUtils; import org.apache.log4j.Logger; import org.springframework.stereotype.Component; -import javax.annotation.PostConstruct; -import javax.inject.Inject; -import javax.naming.ConfigurationException; -import java.io.File; -import java.io.FileInputStream; -import java.io.FileNotFoundException; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.Properties; + +import javax.inject.Inject; @Component public class TungstenServiceImpl implements TungstenService { @@ -51,7 +47,6 @@ public class TungstenServiceImpl implements TungstenService { private static final Logger s_logger = Logger.getLogger(TungstenServiceImpl.class); private ApiConnector _api; - private final String configuration = "plugins/network-elements/tungsten/conf/tungsten.properties"; private VRouterApiConnector _vrouterApi; @Inject @@ -72,49 +67,26 @@ public VRouterApiConnector get_vrouterApi() { return _vrouterApi; } - @PostConstruct @Override - public void init() throws ConfigurationException { - File configFile = PropertiesUtil.findConfigFile(configuration); + public void init() { TungstenProviderVO tungstenProvider = _tungstenProviderService.getTungstenProvider(); if (tungstenProvider != null) { - FileInputStream fileStream = null; - try { - String vrouterHost = null; - String vrouterPort = null; - String hostname = null; - int port = 0; - if (configFile == null) { - throw new FileNotFoundException("Tungsten config file not found!"); - } else { - final Properties configProps = new Properties(); - fileStream = new FileInputStream(configFile); - configProps.load(fileStream); - - vrouterHost = configProps.getProperty("tungsten.vrouter.hostname"); - vrouterPort = configProps.getProperty("tungsten.vrouter.port"); - hostname = tungstenProvider.getHostname(); - port = Integer.parseInt(tungstenProvider.getPort()); - - } - _api = ApiConnectorFactory.build(hostname, port); - _vrouterApi = VRouterApiConnectorFactory.getInstance(vrouterHost, vrouterPort); - } catch (Exception ex) { - s_logger.debug("Exception in configure: " + ex); - ex.printStackTrace(); - throw new ConfigurationException(); - } finally { - IOUtils.closeQuietly(fileStream); - } + String hostname = tungstenProvider.getHostname(); + int port = Integer.parseInt(tungstenProvider.getPort()); + String vrouter = tungstenProvider.getVrouter(); + String vrouterPort = tungstenProvider.getVrouterPort(); + _api = ApiConnectorFactory.build(hostname, port); + _vrouterApi = VRouterApiConnectorFactory.getInstance(vrouter, vrouterPort); } else { _tungstenProviderService.disableTungstenNsp(); } } @Override - public VirtualNetwork createNetworkInTungsten(String networkUuid, String networkName, String projectUuid, String networkIpamUuid, String ipAllocPoolStart, - String ipAllocPoolEnd, String subnetIpPrefix, int subnetIpPrefixLength, String defaultGateway, - boolean isDhcpEnabled, List dnsNameservers, boolean isIpAddrFromStart) { + public VirtualNetwork createNetworkInTungsten(String networkUuid, String networkName, String projectUuid, + String networkIpamUuid, String ipAllocPoolStart, String ipAllocPoolEnd, String subnetIpPrefix, + int subnetIpPrefixLength, String defaultGateway, boolean isDhcpEnabled, List dnsNameservers, + boolean isIpAddrFromStart) { VirtualNetwork network = new VirtualNetwork(); try { if (projectUuid != null) { @@ -123,12 +95,13 @@ public VirtualNetwork createNetworkInTungsten(String networkUuid, String network } network.setUuid(networkUuid); network.setName(networkName); - network.setNetworkIpam(getNetworkIpam(networkName, networkIpamUuid), getVnSubnetsType(ipAllocPoolStart, ipAllocPoolEnd, subnetIpPrefix, - subnetIpPrefixLength, defaultGateway, isDhcpEnabled, dnsNameservers, isIpAddrFromStart)); + network.setNetworkIpam(getNetworkIpam(networkName, networkIpamUuid), + getVnSubnetsType(ipAllocPoolStart, ipAllocPoolEnd, subnetIpPrefix, subnetIpPrefixLength, defaultGateway, + isDhcpEnabled, dnsNameservers, isIpAddrFromStart)); _api.create(network); return (VirtualNetwork) _api.findByFQN(VirtualNetwork.class, getFqnName(network)); } catch (IOException e) { - s_logger.error("Unable to read " + configuration, e); + s_logger.error("Unable to create tungsten network " + networkUuid, e); return null; } } @@ -140,9 +113,8 @@ public VirtualNetwork deleteNetworkFromTungsten(String tungstenNetworkUuid) thro if (network.getVirtualMachineInterfaceBackRefs() != null) throw new ServerApiException(ApiErrorCode.INTERNAL_ERROR, "Failed to delete network"); _api.delete(network); - return network; - } else - throw new InvalidParameterValueException("Unable to find tungsten network with UUID: " + tungstenNetworkUuid); + } + return network; } @Override @@ -154,18 +126,19 @@ public VirtualMachine createVmInTungsten(String vmUuid, String vmName) { _api.create(virtualMachine); return (VirtualMachine) _api.findByFQN(VirtualMachine.class, getFqnName(virtualMachine)); } catch (IOException e) { - s_logger.error("Unable to read " + configuration, e); + s_logger.error("Unable to create tungsten vm " + vmUuid, e); return null; } } @Override - public InstanceIp createInstanceIpInTungsten(String instanceIpName, String tungstenVmInterfaceUuid, String tungstenNetworkUuid, - String tungstenInstanceIpAddress) { + public InstanceIp createInstanceIpInTungsten(String instanceIpName, String tungstenVmInterfaceUuid, + String tungstenNetworkUuid, String tungstenInstanceIpAddress) { InstanceIp instanceIp = new InstanceIp(); try { instanceIp.setName(instanceIpName); - VirtualMachineInterface virtualMachineInterface = (VirtualMachineInterface) _api.findById(VirtualMachineInterface.class, tungstenVmInterfaceUuid); + VirtualMachineInterface virtualMachineInterface = (VirtualMachineInterface) _api.findById( + VirtualMachineInterface.class, tungstenVmInterfaceUuid); VirtualNetwork virtualNetwork = (VirtualNetwork) _api.findById(VirtualNetwork.class, tungstenNetworkUuid); if (virtualNetwork != null) instanceIp.setVirtualNetwork(virtualNetwork); @@ -175,16 +148,18 @@ public InstanceIp createInstanceIpInTungsten(String instanceIpName, String tungs _api.create(instanceIp); return (InstanceIp) _api.findByFQN(InstanceIp.class, getFqnName(instanceIp)); } catch (IOException e) { - s_logger.error("Unable to read " + configuration, e); + s_logger.error("Unable to create tungsten instance ip ", e); return null; } } @Override - public VirtualMachineInterface createVmInterfaceInTungsten(String vmInterfaceName, String tungstenProjectUuid, String tungstenNetworkUuid, - String tungstenVmUuid, String tungstenSecurityGroupUuid, List tungstenVmInterfaceMacAddresses) { + public VirtualMachineInterface createVmInterfaceInTungsten(String vmiUuid, String vmInterfaceName, + String tungstenProjectUuid, String tungstenNetworkUuid, String tungstenVmUuid, String tungstenSecurityGroupUuid, + List tungstenVmInterfaceMacAddresses) { VirtualMachineInterface virtualMachineInterface = new VirtualMachineInterface(); try { + virtualMachineInterface.setUuid(vmiUuid); virtualMachineInterface.setName(vmInterfaceName); Project project = (Project) _api.findById(Project.class, tungstenProjectUuid); VirtualNetwork virtualNetwork = (VirtualNetwork) _api.findById(VirtualNetwork.class, tungstenNetworkUuid); @@ -201,9 +176,10 @@ public VirtualMachineInterface createVmInterfaceInTungsten(String vmInterfaceNam if (tungstenVmInterfaceMacAddresses != null && !tungstenVmInterfaceMacAddresses.isEmpty()) virtualMachineInterface.setMacAddresses(new MacAddressesType(tungstenVmInterfaceMacAddresses)); _api.create(virtualMachineInterface); - return (VirtualMachineInterface) _api.findByFQN(VirtualMachineInterface.class, getFqnName(virtualMachineInterface)); + return (VirtualMachineInterface) _api.findByFQN(VirtualMachineInterface.class, + getFqnName(virtualMachineInterface)); } catch (IOException e) { -// s_logger.error("Unable to read " + configuration, e); + // s_logger.error("Unable to read " + configuration, e); return null; } } @@ -218,16 +194,20 @@ public void expugeVmFromTungsten(String vmUuid) throws IOException { VirtualMachine virtualMachine = (VirtualMachine) _api.findById(VirtualMachine.class, vmUuid); if (virtualMachine == null) return; - if (virtualMachine.getVirtualMachineInterfaceBackRefs() != null && !virtualMachine.getVirtualMachineInterfaceBackRefs().isEmpty()) { + if (virtualMachine.getVirtualMachineInterfaceBackRefs() != null + && !virtualMachine.getVirtualMachineInterfaceBackRefs().isEmpty()) { removeVirtualMachineInterfaceBackRefs(virtualMachine.getVirtualMachineInterfaceBackRefs()); } _api.delete(VirtualMachine.class, virtualMachine.getUuid()); } - public void removeVirtualMachineInterfaceBackRefs(List> virtualMachineInterfaceBackRefs) throws IOException { + public void removeVirtualMachineInterfaceBackRefs( + List> virtualMachineInterfaceBackRefs) throws IOException { for (ObjectReference item : virtualMachineInterfaceBackRefs) { - VirtualMachineInterface virtualMachineInterface = (VirtualMachineInterface) _api.findById(VirtualMachineInterface.class, item.getUuid()); - if (virtualMachineInterface.getInstanceIpBackRefs() != null && !virtualMachineInterface.getInstanceIpBackRefs().isEmpty()) { + VirtualMachineInterface virtualMachineInterface = (VirtualMachineInterface) _api.findById( + VirtualMachineInterface.class, item.getUuid()); + if (virtualMachineInterface.getInstanceIpBackRefs() != null + && !virtualMachineInterface.getInstanceIpBackRefs().isEmpty()) { for (ObjectReference instanceIp : virtualMachineInterface.getInstanceIpBackRefs()) { _api.delete(InstanceIp.class, instanceIp.getUuid()); } @@ -236,16 +216,18 @@ public void removeVirtualMachineInterfaceBackRefs(List dnsNameservers, boolean isIpAddrFromStart) { + @Override + public VnSubnetsType getVnSubnetsType(String ipAllocPoolStart, String ipAllocPoolEnd, String subnetIpPrefix, + int subnetIpPrefixLength, String defaultGateway, boolean isDhcpEnabled, List dnsNameservers, + boolean isIpAddrFromStart) { List allocationPoolTypes = new ArrayList<>(); if (ipAllocPoolStart != null && ipAllocPoolEnd != null) { - allocationPoolTypes.add(new VnSubnetsType.IpamSubnetType.AllocationPoolType(ipAllocPoolStart, ipAllocPoolEnd)); + allocationPoolTypes.add( + new VnSubnetsType.IpamSubnetType.AllocationPoolType(ipAllocPoolStart, ipAllocPoolEnd)); } VnSubnetsType.IpamSubnetType ipamSubnetType = new VnSubnetsType.IpamSubnetType( - new SubnetType(subnetIpPrefix, subnetIpPrefixLength), defaultGateway, - null, isDhcpEnabled, dnsNameservers, allocationPoolTypes, isIpAddrFromStart, null, null, null); + new SubnetType(subnetIpPrefix, subnetIpPrefixLength), defaultGateway, null, isDhcpEnabled, dnsNameservers, + allocationPoolTypes, isIpAddrFromStart, null, null, null); return new VnSubnetsType(Arrays.asList(ipamSubnetType), null); } @@ -261,6 +243,17 @@ public NetworkIpam getNetworkIpam(String networkName, String networkIpamUuid) th return (NetworkIpam) _api.findByFQN(NetworkIpam.class, getFqnName(networkIpam)); } + @Override + public void addTungstenVrouterPort(Port port) throws IOException { + port.setTapInterfaceName(TungstenUtils.getTapName(port.getMacAddress())); + _vrouterApi.addPort(port); + } + + @Override + public void deleteTungstenVrouterPort(String portUuid) throws IOException { + _vrouterApi.deletePort(portUuid); + } + /** * Get the tungsten project that match the project from cloudstack * @@ -275,7 +268,7 @@ public Project getTungstenNetworkProject(Account owner) throws IOException { Domain tungstenDomain; Project tungstenProject; //get the tungsten domain - if (cloudstackDomain != null) { + if (cloudstackDomain.getId() != com.cloud.domain.Domain.ROOT_DOMAIN) { tungstenDomain = (Domain) _api.findById(Domain.class, cloudstackDomain.getUuid()); if (tungstenDomain == null) { tungstenDomain = createDomainInTungsten(cloudstackDomain.getName(), cloudstackDomain.getUuid()); @@ -287,10 +280,11 @@ public Project getTungstenNetworkProject(Account owner) throws IOException { if (cloudstackProject != null) { tungstenProject = (Project) _api.findById(Project.class, cloudstackProject.getUuid()); if (tungstenProject == null) { - tungstenProject = createProjectInTungsten(cloudstackProject.getName(), cloudstackProject.getUuid(), tungstenDomain); + tungstenProject = createProjectInTungsten(cloudstackProject.getName(), cloudstackProject.getUuid(), + tungstenDomain); } } else { - tungstenProject = getDefaultTungstenProject(tungstenDomain.getName()); + tungstenProject = getDefaultTungstenProject(); } return tungstenProject; } @@ -304,7 +298,8 @@ public Project getTungstenNetworkProject(Account owner) throws IOException { * @return the project created in tungsten * @throws IOException */ - public Project createProjectInTungsten(String projectName, String projectUuid, Domain tungstenDomain) throws IOException { + public Project createProjectInTungsten(String projectName, String projectUuid, Domain tungstenDomain) + throws IOException { Project tungstenProject = new Project(); tungstenProject.setDisplayName(projectName); tungstenProject.setName(projectName); @@ -362,19 +357,11 @@ public Project createDefaultProject(String tungstenDomain) throws IOException { /** * Get the tungsten domain default project * - * @param tungstenDomain * @return * @throws IOException */ - public Project getDefaultTungstenProject(String tungstenDomain) throws IOException { - Project project; - if (tungstenDomain == null) - project = (Project) _api.findByFQN(Project.class, TUNGSTEN_DEFAULT_DOMAIN + ":" + TUNGSTEN_DEFAULT_PROJECT); - else - project = (Project) _api.findByFQN(Project.class, tungstenDomain + ":" + tungstenDomain + "-default-project"); - if (project == null) - project = createDefaultProject(tungstenDomain); - return project; + public Project getDefaultTungstenProject() throws IOException { + return (Project) _api.findByFQN(Project.class, TUNGSTEN_DEFAULT_DOMAIN + ":" + TUNGSTEN_DEFAULT_PROJECT); } /** @@ -397,4 +384,87 @@ public String getFqnName(ApiObjectBase obj) { sb.deleteCharAt(sb.toString().length() - 1); return sb.toString(); } + + @Override + public ApiObjectBase getObject(Class obj, String uuid) throws IOException { + return _api.findById(obj, uuid); + } + + @Override + public void deleteObject(Class obj, String uuid) throws IOException { + _api.delete(obj, uuid); + } + + @Override + public NetworkIpam getDefaultProjectNetworkIpam(Project project) throws IOException { + List names = new ArrayList<>(); + Domain domain = (Domain) _api.findById(Domain.class, project.getParentUuid()); + names.add(domain.getName()); + names.add(project.getName()); + names.add(TUNGSTEN_DEFAULT_IPAM); + String ipamUuid = _api.findByName(NetworkIpam.class, names); + if (ipamUuid == null) { + NetworkIpam defaultIpam = new NetworkIpam(); + defaultIpam.setName(TUNGSTEN_DEFAULT_IPAM); + defaultIpam.setParent(project); + _api.create(defaultIpam); + ipamUuid = defaultIpam.getUuid(); + } + return (NetworkIpam) _api.findById(NetworkIpam.class, ipamUuid); + } + + @Override + public VirtualNetwork createTungstenVirtualNetwork(Network network, Project project, NetworkIpam networkIpam, + VnSubnetsType subnet) { + try { + VirtualNetwork virtualNetwork = new VirtualNetwork(); + virtualNetwork.setUuid(network.getUuid()); + virtualNetwork.setName(network.getName()); + virtualNetwork.addNetworkIpam(networkIpam, subnet); + virtualNetwork.setParent(project); + _api.create(virtualNetwork); + return (VirtualNetwork) _api.findById(VirtualNetwork.class, virtualNetwork.getUuid()); + } catch (IOException e) { + s_logger.error("Unable to create tungsten network", e); + return null; + } + } + + @Override + public InstanceIp createInstanceIpInTungsten(VirtualNetwork vn, VirtualMachineInterface vmi, NicProfile nic) { + try { + InstanceIp instanceIp = new InstanceIp(); + instanceIp.setName(TungstenUtils.getInstanceIpName(nic.getId())); + instanceIp.setVirtualNetwork(vn); + instanceIp.setVirtualMachineInterface(vmi); + instanceIp.setAddress(nic.getIPv4Address()); + _api.create(instanceIp); + return (InstanceIp) _api.findById(InstanceIp.class, instanceIp.getUuid()); + } catch (IOException e) { + s_logger.error("Unable to create tungsten instance ip", e); + return null; + } + } + + @Override + public VirtualMachineInterface createVmInterfaceInTungsten(NicProfile nicProfile, VirtualNetwork vn, + VirtualMachine vm, Project project) { + VirtualMachineInterface virtualMachineInterface = new VirtualMachineInterface(); + try { + virtualMachineInterface.setUuid(nicProfile.getUuid()); + virtualMachineInterface.setName(TungstenUtils.getVmiName(nicProfile.getId())); + virtualMachineInterface.setVirtualNetwork(vn); + virtualMachineInterface.setVirtualMachine(vm); + virtualMachineInterface.setParent(project); + MacAddressesType macAddressesType = new MacAddressesType(); + macAddressesType.addMacAddress(nicProfile.getMacAddress()); + virtualMachineInterface.setMacAddresses(macAddressesType); + _api.create(virtualMachineInterface); + return (VirtualMachineInterface) _api.findById(VirtualMachineInterface.class, + virtualMachineInterface.getUuid()); + } catch (IOException e) { + s_logger.error("Unable to create tungsten virtual machine interface", e); + return null; + } + } } diff --git a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/Port.java b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/Port.java index af0bf3445297..653d1053a0ce 100644 --- a/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/Port.java +++ b/plugins/network-elements/tungsten/src/main/java/org/apache/cloudstack/network/tungsten/vrouter/Port.java @@ -41,6 +41,9 @@ public class Port { @SerializedName("ip6-address") private String ipv6Address = NONE; + @SerializedName("vhostuser-mode") + private int vifType = 0; + public String getId() { return id; } @@ -136,4 +139,12 @@ public String getIpv6Address() { public void setIpv6Address(final String ipv6Address) { this.ipv6Address = ipv6Address; } + + public int getVifType() { + return vifType; + } + + public void setVifType(final int vifType) { + this.vifType = vifType; + } } diff --git a/ui/l10n/en.js b/ui/l10n/en.js index 50a504ad1dc0..174f82e2df84 100644 --- a/ui/l10n/en.js +++ b/ui/l10n/en.js @@ -1934,6 +1934,8 @@ var dictionary = { "label.tungsten.delete.provider":"Delete tungsten provider", "label.tungsten.provider.hostname":"Provider hostname", "label.tungsten.provider.port":"Provider port", + "label.tungsten.provider.vrouter":"Provider vrouter", + "label.tungsten.provider.vrouterport":"Provider vrouter port", "label.tungsten.action.delete.provider":"Delete provider", "label.vpn":"VPN", "label.vpn.customer.gateway":"VPN Customer Gateway", diff --git a/ui/scripts/system.js b/ui/scripts/system.js index 0a942f6c3a3f..2c3727c2043e 100755 --- a/ui/scripts/system.js +++ b/ui/scripts/system.js @@ -4866,6 +4866,12 @@ }, tungstenproviderport: { label: 'label.tungsten.provider.port' + }, + tungstenprovidervrouter: { + label: 'label.tungsten.provider.vrouter' + }, + tungstenprovidervrouterport: { + label: 'label.tungsten.provider.vrouterport' } }, dataProvider: function (args) { @@ -4895,6 +4901,12 @@ }, tungstenproviderport: { label: 'label.tungsten.provider.port' + }, + tungstenprovidervrouter: { + label: 'label.tungsten.provider.vrouter' + }, + tungstenprovidervrouterport: { + label: 'label.tungsten.provider.vrouterport' } }], dataProvider: function (args) { @@ -4977,6 +4989,18 @@ validation: { required: true } + }, + vrouter: { + label: 'label.tungsten.provider.vrouter', + validation: { + required: true + } + }, + vrouterport: { + label: 'label.tungsten.provider.vrouterport', + validation: { + required: true + } } } }, @@ -22010,7 +22034,9 @@ nspid: nspMap[ "Tungsten"].id, tungstenproviderhostname: args.data.hostname, name: args.data.name, - tungstenproviderport: args.data.port + tungstenproviderport: args.data.port, + tungstenprovidervrouter: args.data.vrouter, + tungstenprovidervrouterport: args.data.vrouterport }, type: "POST", success: function (json) { diff --git a/ui/scripts/ui-custom/zoneWizard.js b/ui/scripts/ui-custom/zoneWizard.js new file mode 100644 index 000000000000..de91ca03667d --- /dev/null +++ b/ui/scripts/ui-custom/zoneWizard.js @@ -0,0 +1,1437 @@ +// 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. +(function($, cloudStack) { + /** + * Serialize form data as object + */ + var getData = function($wizard, options) { + if (!options) options = {}; + + var $forms = $wizard.find('form').filter(function() { + return !options.all ? !$(this).closest('.multi-edit').length : true; + }); + var $physicalNetworkItems = $wizard.find( + '.steps .setup-physical-network .select-container.multi' + ).filter(':not(.disabled)'); + var $publicTrafficItems = $wizard.find( + '.steps .setup-public-traffic .data-body .data-item'); + var $storageTrafficItems = $wizard.find( + '.steps .setup-storage-traffic .data-body .data-item'); + var groupedForms = {}; + + if ($physicalNetworkItems.find('li.traffic-type-draggable.storage').length) { + $wizard.find('li.conditional.storage-traffic').show(); + } else { + $wizard.find('li.conditional.storage-traffic').hide(); + } + + if (options.all) { + return cloudStack.serializeForm($forms, { + escapeSlashes: true + }); + } + + // Group form fields together, by form ID + $forms.each(function() { + var $form = $(this); + var id = $form.attr('rel'); + + if (!id) return true; + + groupedForms[id] = cloudStack.serializeForm($form, { + escapeSlashes: true + }); + + return true; + }); + + // Get physical network data + groupedForms.physicalNetworks = $.map( + $physicalNetworkItems, + function(network) { + var $network = $(network); + var $guestForm = $wizard.find('form[guest-network-id=' + $network.index() + ']'); + var trafficTypeConfiguration = {}; + + $network.find('.traffic-type-draggable').each(function() { + var $trafficType = $(this); + var trafficTypeID = $trafficType.attr('traffic-type-id'); + + + trafficTypeConfiguration[trafficTypeID] = $trafficType.data('traffic-type-data'); + }); + + return { + id: $network.index(), + name: $network.find('.field.name input[type=text]').val(), + isolationMethod: $network.find('.field.name select').val(), + + // Traffic type list + trafficTypes: $.map( + $network.find('.traffic-type-draggable'), + function(trafficType) { + var $trafficType = $(trafficType); + + return $trafficType.attr('traffic-type-id'); + } + ), + + // Traffic type configuration data + trafficTypeConfiguration: trafficTypeConfiguration, + + guestConfiguration: $guestForm.length ? cloudStack.serializeForm($guestForm) : null + }; + } + ); + + // Get public traffic data (multi-edit) + groupedForms.publicTraffic = $.map( + $publicTrafficItems, + function(publicTrafficItem) { + var $publicTrafficItem = $(publicTrafficItem); + var publicTrafficData = {}; + var fields = [ + 'gateway', + 'netmask', + 'vlanid', + 'startip', + 'endip' + ]; + + $(fields).each(function() { + publicTrafficData[this] = + $publicTrafficItem.find('td.' + this + ' span').html(); + }); + + return publicTrafficData; + } + ); + + // Get storage traffic data (multi-edit) + groupedForms.storageTraffic = $.map( + $storageTrafficItems, + function(storageTrafficItem) { + var $storageTrafficItem = $(storageTrafficItem); + var storageTrafficData = {}; + var fields = [ + 'gateway', + 'netmask', + 'vlan', + 'startip', + 'endip' + ]; + + $(fields).each(function() { + storageTrafficData[this] = + $storageTrafficItem.find('td.' + this + ' span').html(); + }); + + return storageTrafficData; + } + ); + + // Hack to fix forward slash JS error + $.each(groupedForms, function(key1, value1) { + $.each(value1, function(key2, value2) { + if (typeof value2 == 'string') { + groupedForms[key1][key2] = value2.replace(/__forwardSlash__/g, '\/'); + } + }); + }); + + // Include zone network type + if (groupedForms.zone) { + groupedForms.zone.networkType = $forms.find('input[name=network-model]:checked').val(); + + // Include zone isolation mode, supported for Advanced zones only + if (groupedForms.zone.networkType == 'Advanced') { + groupedForms.zone.sgEnabled = $forms.find('input[name=zone-advanced-sg-enabled]') + .is(':checked') ? true : false; + } + } + + return groupedForms; + }; + + /** + * Handles validation for custom UI components + */ + var customValidation = { + networkRanges: function($form) { + if ($form.closest('.multi-edit').find('.data-item').length) { + return true; + } + + cloudStack.dialog.notice({ + message: _l('message.please.add.at.lease.one.traffic.range') + }); + return false; + }, + + physicalNetworks: function($form) { + var $enabledPhysicalNetworks = $form.filter(':not(.disabled)').filter(function() { + return $(this).find('.traffic-type-draggable').length; + }); + var $trafficTypes = $enabledPhysicalNetworks.find('.traffic-type-draggable'); + var $configuredTrafficTypes = $trafficTypes.filter(function() { + var $trafficType = $(this); + + return ($trafficType.data('traffic-type-data') != null); + }); + + if ($enabledPhysicalNetworks.length > 1 && + $configuredTrafficTypes.length != $trafficTypes.length) { + cloudStack.dialog.notice({ + message: _l('message.configure.all.traffic.types') + }); + + return false; + } + + return true; + } + }; + + /** + * Determine if UI components in step should be custom-validated + * (i.e., not a standard form) + */ + var checkCustomValidation = function($step) { + var $multiEditForm = $step.find('.multi-edit form'); + var $physicalNetworks = $step.find('.select-container.multi'); + var isCustomValidated; + + if ($multiEditForm.length) { + isCustomValidated = customValidation.networkRanges($multiEditForm); + } else if ($physicalNetworks.length) { + isCustomValidated = customValidation.physicalNetworks($physicalNetworks); + } else { + isCustomValidated = true; + } + + return isCustomValidated; + }; + + var isAdvancedNetwork = function($wizard) { + return getData($wizard, { + all: true + })['network-model'] == 'Advanced'; + }; + + /** + * Setup physical network wizard UI + */ + var physicalNetwork = { + init: function($wizard) { + var $existingPhysicalNetworks = physicalNetwork.getNetworks($wizard); + + // Initialize physical networks + if (!$existingPhysicalNetworks.length) { + physicalNetwork.add($wizard); + } else if (!isAdvancedNetwork($wizard)) { + $existingPhysicalNetworks.filter(':first').siblings().each(function() { + physicalNetwork.remove($(this)); + }); + } + + physicalNetwork.updateNetworks(physicalNetwork.getNetworks($wizard)); + + $wizard.find('.traffic-types-drag-area ul li').removeClass('required disabled clone'); + + // Setup clone traffic types + $(physicalNetwork.cloneTrafficTypes($wizard)).each(function() { + var trafficTypeID = this; + + $wizard.find('.traffic-types-drag-area ul li').filter(function() { + return $(this).hasClass(trafficTypeID); + }).addClass('clone'); + }); + + // Setup required traffic types + $(physicalNetwork.requiredTrafficTypes($wizard)).each(function() { + var trafficTypeID = this; + var $firstPhysicalNetwork = physicalNetwork.getNetworks($wizard).filter(':first'); + + // First physical network gets required traffic types + physicalNetwork.assignTrafficType(trafficTypeID, $firstPhysicalNetwork); + + $wizard.find('.traffic-types-drag-area ul li').filter(function() { + return $(this).hasClass(trafficTypeID); + }).addClass('required'); + }); + + // Setup disabled traffic types + $(physicalNetwork.disabledTrafficTypes($wizard)).each(function() { + var trafficTypeID = this; + var $trafficType = physicalNetwork.getTrafficType(this, $wizard); + + physicalNetwork.unassignTrafficType($trafficType); + + $wizard.find('.traffic-types-drag-area ul li').filter(function() { + return $(this).hasClass(trafficTypeID); + }).addClass('disabled'); + }); + }, + + /** + * Traffic type edit dialog + */ + editTrafficTypeDialog: function($trafficType) { + var trafficData = $trafficType.data('traffic-type-data') ? + $trafficType.data('traffic-type-data') : {}; + var hypervisor = getData($trafficType.closest('.zone-wizard')).zone.hypervisor; + var zoneType = getData($trafficType.closest('.zone-wizard')).zone.networkType; + var fields; + + if (hypervisor == 'VMware') { + fields = { + vSwitchName: { + label: 'label.vswitch.name' , + defaultValue: trafficData.vSwitchName + }, + vlanId: { + label: 'label.vlan.id', + defaultValue: trafficData.vlanId + } + }; + + if(zoneType == 'Advanced') { + if(trafficData.vSwitchType == null) { + var useDvs = false; + $.ajax({ + url: createURL('listConfigurations'), + data: { + name: 'vmware.use.dvswitch' + }, + async: false, + success: function(json) { + if (json.listconfigurationsresponse.configuration[0].value == 'true') { + useDvs = true; + } + } + }); + if (useDvs == true) { + var useNexusDvs = false; + $.ajax({ + url: createURL('listConfigurations'), + data: { + name: 'vmware.use.nexus.vswitch' + }, + async: false, + success: function(json) { + if (json.listconfigurationsresponse.configuration[0].value == 'true') { + useNexusDvs = true; + } + } + }); + if (useNexusDvs == true) { + trafficData.vSwitchType = 'nexusdvs'; + fields.vSwitchName.defaultValue = 'epp0'; + } else { + trafficData.vSwitchType = 'vmwaredvs'; + fields.vSwitchName.defaultValue = 'dvSwitch0'; + } + } else { //useDvs == false + trafficData.vSwitchType = 'vmwaresvs'; + fields.vSwitchName.defaultValue = 'vSwitch0'; + } + } + + $.extend(fields, { + vSwitchType: { + label: 'label.vSwitch.type', + select: function (args) { + args.response.success({ + data: [{ + id: 'nexusdvs', + description: 'Cisco Nexus 1000v Distributed Virtual Switch' + }, { + id: 'vmwaresvs', + description: 'VMware vNetwork Standard Virtual Switch' + }, { + id: 'vmwaredvs', + description: 'VMware vNetwork Distributed Virtual Switch' + }] + }); + }, + defaultValue: trafficData.vSwitchType + } + }); + } + } else { + fields = { + label: { + label: hypervisor + ' ' + _l('label.traffic.label'), + defaultValue: trafficData.label + } + }; + } + + cloudStack.dialog.createForm({ + form: { + title: _l('label.edit.traffic.type'), + desc: _l('message.edit.traffic.type'), + fields: fields + }, + + after: function(args) { + $trafficType.data('traffic-type-data', args.data); + } + }); + }, + + /** + * Get required traffic type IDs for proper validation + */ + requiredTrafficTypes: function($wizard) { + return cloudStack.zoneWizard.requiredTrafficTypes({ + data: getData($wizard) + }); + }, + + /** + * Get required traffic type IDs for proper validation + */ + disabledTrafficTypes: function($wizard) { + return cloudStack.zoneWizard.disabledTrafficTypes({ + data: getData($wizard) + }); + }, + + /** + * Get clone-type traffic type IDs for proper validation + */ + cloneTrafficTypes: function($wizard) { + return cloudStack.zoneWizard.cloneTrafficTypes({ + data: getData($wizard) + }); + }, + + /** + * Physical network step: Renumber network form items + */ + renumberFormItems: function($container) { + var $items = $container.find('.select-container.multi'); + + $items.each(function() { + var $item = $(this); + var $networkName = $item.find('.field.name input[type=text]'); + var $networkId = $item.find('input[name=id]'); + var $networkTypes = $item.find('.field.network-types input'); + var index = $item.index(); + + $networkId.val(index); + $networkName.attr('name', 'physicalNetworks[' + index + ']' + '.name'); + $networkTypes.val(index); + }); + }, + + /** + * Get main physical network wizard step container + * + * @param $elem Any elem within the container + */ + getMainContainer: function($elem) { + return $elem.closest('.steps .setup-physical-network'); + }, + + /** + * Returns traffic elem + * + * @param trafficTypeID ID of desired traffic type + */ + getTrafficType: function(trafficTypeID, $container) { + var $trafficType = $container.find('li.traffic-type-draggable').filter(function() { + return $(this).attr('traffic-type-id') == trafficTypeID; + }); + + if (physicalNetwork.isTrafficTypeClone($trafficType) && !$container.closest('.select-container.multi').length) { + // Get traffic type from original container + return $trafficType.filter(function() { + return $(this).closest( + physicalNetwork.getOriginalTrafficContainer($trafficType) + ).length; + }); + } + + return $trafficType; + }, + + /** + * Get original drag container for traffic type elem + * + * @param $trafficType Traffic type elem + */ + getOriginalTrafficContainer: function($trafficType) { + var $dragContainer = physicalNetwork.getMainContainer($trafficType) + .find('.traffic-types-drag-area ul > li') + .filter(function() { + return $(this).hasClass($trafficType.attr('traffic-type-id')); + }) + .find('ul'); + + return $dragContainer; + }, + + /** + * Get all physical networks + * + * @param $container Physical network step - main container + */ + getNetworks: function($container) { + return $container.find('.select-container.multi'); + }, + + /** + * Determine if traffic type is a 'cloned' type + * + * @param $trafficType + */ + isTrafficTypeClone: function($trafficType) { + return physicalNetwork.getOriginalTrafficContainer($trafficType).parent().hasClass('clone'); + }, + + /** + * Assigns traffic type to specified physical network + * + * @param trafficTypeID ID of desired traffic type + * @param $physicalNetwork Physical network elem + */ + assignTrafficType: function(trafficTypeID, $physicalNetwork, data) { + var $container = physicalNetwork.getMainContainer($physicalNetwork); + var $trafficType = physicalNetwork.getTrafficType(trafficTypeID, $container); + var $dropArea = $physicalNetwork.find('.drop-container ul'); + + if ($physicalNetwork.find('.traffic-type-draggable[traffic-type-id=' + trafficTypeID + ']').length) return false; + + if (physicalNetwork.isTrafficTypeClone($trafficType)) { + if (!physicalNetwork.getTrafficType(trafficTypeID, $physicalNetwork).length) { + $trafficType = $trafficType.clone() + .removeClass('disabled') + .appendTo($dropArea) + .draggable(physicalNetwork.draggableOptions($physicalNetwork.closest('.zone-wizard'))); + } else { + return false; + } + } else { + $trafficType.appendTo($dropArea); + } + + if (data) { + $trafficType.data('traffic-type-data', data); + } + + physicalNetwork.updateNetworks($.merge($physicalNetwork, $physicalNetwork.siblings())); + + return $trafficType; + }, + + /** + * Assigns traffic type to original drag container + * + * @param trafficTypeID ID of desired traffic type + * @param $container Physical network wizard step container + * @param $physicalNetwork (optional) Specific physical network to remove from -- only for clones + */ + unassignTrafficType: function($trafficType) { + var $wizard = $trafficType.closest('.zone-wizard'); + var $originalContainer = physicalNetwork.getOriginalTrafficContainer($trafficType); + var $physicalNetworks = physicalNetwork.getNetworks($wizard); + var trafficTypeID = $trafficType.attr('traffic-type-id'); + + if (!physicalNetwork.isTrafficTypeClone($trafficType) && + $.inArray(trafficTypeID, physicalNetwork.requiredTrafficTypes($wizard)) == -1) { + $trafficType.appendTo($originalContainer); + } else { + physicalNetwork.assignTrafficType( + trafficTypeID, + $physicalNetworks.filter(':first') + ); + + if (physicalNetwork.isTrafficTypeClone($trafficType) && + $physicalNetworks.find('.traffic-type-draggable[traffic-type-id=' + trafficTypeID + ']').length > 1) { + $trafficType.remove(); + } + } + + return $trafficType; + }, + + /** + * Returns true if new physical network item needs to be added + */ + needsNewNetwork: function($containers) { + // Basic zones do not have multiple physical networks + if (!isAdvancedNetwork($containers.closest('.zone-wizard'))) + return false; + + var $emptyContainers = $containers.filter(function() { + return !$(this).find('li').length; + }); + + return !$emptyContainers.length ? $containers.length : false; + }, + + /** + * Cleanup physical network containers + */ + updateNetworks: function($containers) { + var $mainContainer = physicalNetwork.getMainContainer($containers); + var $allPhysicalNetworks = physicalNetwork.getNetworks($mainContainer); + var containerTotal = isAdvancedNetwork($containers.closest('.zone-wizard')) ? + 2 : 1; + + $allPhysicalNetworks.each(function() { + var $ul = $(this).find('.drop-container ul'); + + if (!$(this).find('li').length) { + $(this).addClass('disabled'); + $ul.fadeOut(); + } else { + $(this).removeClass('disabled'); + $ul.show(); + } + }); + + $containers.each(function() { + var $currentContainer = $(this); + if (!$currentContainer.find('li').length && + $containers.length > containerTotal) { + $currentContainer.remove(); + } + }); + + $containers = $containers.closest('.setup-physical-network') + .find('.select-container.multi'); + + if (physicalNetwork.needsNewNetwork($containers)) { + physicalNetwork.add($mainContainer.parent()); + } + + $containers.filter(':first').find('.remove.physical-network').remove(); + + return $containers; + }, + + /** + * Default options for initializing traffic type draggables + */ + draggableOptions: function($wizard) { + return { + appendTo: $wizard, + helper: 'clone', + + // Events + start: function(event, ui) { + $(this).addClass('disabled'); + }, + + stop: function(event, ui) { + $(this).removeClass('disabled'); + }, + + cancel: '.edit-traffic-type' + }; + }, + + /** + * Physical network step: Generate new network element + */ + add: function($wizard) { + var $container = $wizard.find('.setup-physical-network .content.input-area form'); + var $physicalNetworkItem = $('
    ').addClass('select-container multi'); + var $deleteButton = $('
    ').addClass('button remove physical-network') + .attr({ + title: _l('label.remove.this.physical.network') + }) + .append('').addClass('icon').html(' '); + var $icon = $('
    ').addClass('physical-network-icon'); + + var $nameField = $('
    ').addClass('field name').append( + $('
    ').addClass('name').append( + $('