This commit is contained in:
Pranav Saxena 2013-06-05 23:56:06 +05:30
commit 81d2a70bf3
21 changed files with 702 additions and 340 deletions

View File

@ -36,11 +36,3 @@ done
export CLASSPATH
PATH=/sbin:/usr/sbin:$PATH
export PATH
#catalina.out owned by `cloud` not `root`
if [ ! -f $TOMCAT_LOG ]; then
touch $TOMCAT_LOG
chown $TOMCAT_USER:$TOMCAT_USER $TOMCAT_LOG
else
chown $TOMCAT_USER:$TOMCAT_USER $TOMCAT_LOG
fi

View File

@ -0,0 +1,22 @@
<!-- 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.
-->
<!ENTITY PRODUCT "CloudStack">
<!ENTITY BOOKID "Technical Documentation">
<!ENTITY YEAR "2013">
<!ENTITY HOLDER "Apache Software Foundation">

View File

@ -0,0 +1,52 @@
<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "CloudStack_GSoC_Guide.ent">
%BOOK_ENTITIES;
<!ENTITY % xinclude SYSTEM "http://www.docbook.org/xml/4.4/xinclude.mod">
%xinclude;
]>
<!-- 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.
-->
<book>
<bookinfo id="cloudstack_gsoc_2013">
<title>&PRODUCT; Guide for the 2013 Google Summer of Code</title>
<productname>Apache CloudStack</productname>
<productnumber>4.3.0</productnumber>
<edition>1</edition>
<pubsnumber></pubsnumber>
<abstract>
<para>
Guide for 2013 Google Summer of Code Projects.
</para>
</abstract>
<corpauthor>
<inlinemediaobject>
<imageobject>
<imagedata fileref="Common_Content/images/title_logo.svg" format="SVG" />
</imageobject>
</inlinemediaobject>
</corpauthor>
<xi:include href="Common_Content/Legal_Notice.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
<xi:include href="Author_Group.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
</bookinfo>
<xi:include href="gsoc-tuna.xml" xmlns:xi="http://www.w3.org/2001/XInclude" />
</book>

28
docs/en-US/gsoc-tuna.xml Normal file
View File

@ -0,0 +1,28 @@
<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "CloudStack_GSoC_Guide.ent">
%BOOK_ENTITIES;
]>
<!-- 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.
-->
<chapter id="gsoc-tuna">
<title>Nguyen's 2013 GSoC Proposal</title>
<para>This chapter describes Nguyen 2013 Google Summer of Code project within the &PRODUCT; ASF project. It is a copy paste of the submitted proposal.</para>
</chapter>

View File

@ -27,7 +27,8 @@
Basic zones and security groups-enabled Advanced zones. For security groups-enabled Advanced
zones, it implies multiple subnets can be added to the same VLAN. With the addition of this
feature, you will be able to add IP address ranges from the same subnet or from a different one
when IP address are exhausted. To support this feature, the capability of
when IP address are exhausted. This would in turn allows you to employ higher number of subnets
and thus reduce the address management overhead. To support this feature, the capability of
<code>createVlanIpRange</code> API is extended to add IP ranges also from a different
subnet.</para>
<para>Ensure that you manually configure the gateway of the new subnet before adding the IP range.

57
docs/en-US/pvlan.xml Normal file
View File

@ -0,0 +1,57 @@
<?xml version='1.0' encoding='utf-8' ?>
<!DOCTYPE section PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN" "http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
<!ENTITY % BOOK_ENTITIES SYSTEM "cloudstack.ent">
%BOOK_ENTITIES;
]>
<!-- 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.
-->
<section id="pvlan">
<title>Isolation in Advanced Zone Using Private VLAN</title>
<para/>
<section id="about-pvlan">
<title>About Private VLAN</title>
<para>In an Ethernet switch, a VLAN is a broadcast domain in which hosts can establish direct
communication with each another at Layer 2. Private VLAN is designed as an extension of VLAN
standard to add further segmentation of the logical broadcast domain. A regular VLAN is a
single broadcast domain, whereas a private VLAN partitions a larger VLAN broadcast domain into
smaller sub-domains. A sub-domain is represented by a pair of VLANs: a Primary VLAN and a
Secondary VLAN. The original VLAN that is being divided into smaller groups is called
Primary, That implies all VLAN pairs in a private VLAN share the same Primary VLAN. All the
secondary VLANs exist only inside the Primary. Each Secondary VLAN has a specific VLAN ID
associated to it, which differentiates one sub-domain from another.</para>
<para>For further reading:</para>
<itemizedlist>
<listitem>
<para><ulink
url="http://www.cisco.com/en/US/docs/switches/lan/catalyst3750/software/release/12.2_25_see/configuration/guide/swpvlan.html#wp1038379"
>Understanding Private VLANs</ulink></para>
</listitem>
<listitem>
<para><ulink url="http://tools.ietf.org/html/rfc5517">Cisco Systems' Private VLANs: Scalable
Security in a Multi-Client Environment</ulink></para>
</listitem>
<listitem>
<para><ulink url="http://kb.vmware.com">Private VLAN (PVLAN) on vNetwork Distributed Switch
- Concept Overview (1010691)</ulink></para>
</listitem>
</itemizedlist>
</section>
<section id="prereq-pvlan">
<title>Prerequisites</title>
<para>Ensure that you configure private VLAN on your physical switches out-of-band.</para>
</section>
</section>

View File

@ -0,0 +1,27 @@
# Publican configuration file for CloudStack Complete Documentation Set
# Contains all technical docs except release notes
# Config::Simple 4.58
# Tue May 29 00:57:27 2012
#
# 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.
xml_lang: en-US
type: Book
docname: CloudStack_GSoC_Guide
brand: cloudstack
chunk_first: 1
chunk_section_depth: 1

View File

@ -54,10 +54,9 @@ public interface UserVmDao extends GenericDao<UserVmVO, Long> {
/**
* List user vm instances with virtualized networking (i.e. not direct attached networking) for the given account and datacenter
* @param accountId will search for vm instances belonging to this account
* @param dcId will search for vm instances in this zone
* @return the list of vm instances owned by the account in the given data center that have virtualized networking (not direct attached networking)
*/
List<UserVmVO> listVirtualNetworkInstancesByAcctAndZone(long accountId, long dcId, long networkId);
List<UserVmVO> listVirtualNetworkInstancesByAcctAndNetwork(long accountId, long networkId);
List<UserVmVO> listByNetworkIdAndStates(long networkId, State... states);

View File

@ -283,11 +283,10 @@ public class UserVmDaoImpl extends GenericDaoBase<UserVmVO, Long> implements Use
}
@Override
public List<UserVmVO> listVirtualNetworkInstancesByAcctAndZone(long accountId, long dcId, long networkId) {
public List<UserVmVO> listVirtualNetworkInstancesByAcctAndNetwork(long accountId, long networkId) {
SearchCriteria<UserVmVO> sc = AccountDataCenterVirtualSearch.create();
sc.setParameters("account", accountId);
sc.setParameters("dc", dcId);
sc.setJoinParameters("nicSearch", "networkId", networkId);
return listBy(sc);

View File

@ -216,6 +216,8 @@ ln -sf /var/log/%{name}/management ${RPM_BUILD_ROOT}%{_datadir}/%{name}-manageme
ln -sf /var/cache/%{name}/management/temp ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/temp
ln -sf /var/cache/%{name}/management/work ${RPM_BUILD_ROOT}%{_datadir}/%{name}-management/work
/bin/touch ${RPM_BUILD_ROOT}%{_localstatedir}/log/%{name}/management/catalina.out
install -D client/target/utilities/bin/cloud-migrate-databases ${RPM_BUILD_ROOT}%{_bindir}/%{name}-migrate-databases
install -D client/target/utilities/bin/cloud-set-guest-password ${RPM_BUILD_ROOT}%{_bindir}/%{name}-set-guest-password
install -D client/target/utilities/bin/cloud-set-guest-sshkey ${RPM_BUILD_ROOT}%{_bindir}/%{name}-set-guest-sshkey
@ -519,6 +521,7 @@ fi
%dir %attr(0770,root,root) %{_localstatedir}/log/%{name}-management
%{_defaultdocdir}/%{name}-management-%{version}/LICENSE
%{_defaultdocdir}/%{name}-management-%{version}/NOTICE
%attr(0644,cloud,cloud) %{_localstatedir}/log/%{name}/management/catalina.out
%files agent
%attr(0755,root,root) %{_bindir}/%{name}-setup-agent

View File

@ -1835,9 +1835,8 @@ public class LoadBalancingRulesManagerImpl<Type> extends ManagerBase implements
}
}
IPAddressVO addr = _ipAddressDao.findById(loadBalancer.getSourceIpAddressId());
List<UserVmVO> userVms = _vmDao.listVirtualNetworkInstancesByAcctAndZone(loadBalancer.getAccountId(),
addr.getDataCenterId(), loadBalancer.getNetworkId());
List<UserVmVO> userVms = _vmDao.listVirtualNetworkInstancesByAcctAndNetwork(loadBalancer.getAccountId(),
loadBalancer.getNetworkId());
for (UserVmVO userVm : userVms) {
// if the VM is destroyed, being expunged, in an error state, or in

View File

@ -30,6 +30,7 @@ import java.util.Comparator;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
@ -373,15 +374,6 @@ import org.apache.cloudstack.api.command.user.vmsnapshot.DeleteVMSnapshotCmd;
import org.apache.cloudstack.api.command.user.vmsnapshot.ListVMSnapshotCmd;
import org.apache.cloudstack.api.command.user.vmsnapshot.RevertToVMSnapshotCmd;
import org.apache.cloudstack.api.command.user.volume.*;
import org.apache.cloudstack.api.command.user.volume.AttachVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.CreateVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.DeleteVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.DetachVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.ExtractVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.ListVolumesCmd;
import org.apache.cloudstack.api.command.user.volume.MigrateVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.ResizeVolumeCmd;
import org.apache.cloudstack.api.command.user.volume.UploadVolumeCmd;
import org.apache.cloudstack.api.command.user.vpc.CreateStaticRouteCmd;
import org.apache.cloudstack.api.command.user.vpc.CreateVPCCmd;
import org.apache.cloudstack.api.command.user.vpc.DeleteStaticRouteCmd;
@ -1184,10 +1176,11 @@ public class ManagementServerImpl extends ManagerBase implements ManagementServe
allHosts.remove(srcHost);
// Check if the host has storage pools for all the volumes of the vm to be migrated.
for (Host host : allHosts) {
for (Iterator<HostVO> iterator = allHosts.iterator(); iterator.hasNext();) {
Host host = iterator.next();
Map<Volume, List<StoragePool>> volumePools = findSuitablePoolsForVolumes(vmProfile, host);
if (volumePools.isEmpty()) {
allHosts.remove(host);
iterator.remove();
} else {
if (!host.getClusterId().equals(srcHost.getClusterId()) || usesLocal) {
requiresStorageMotion.put(host, true);

View File

@ -755,6 +755,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
}
if (vm.getState() == State.Running && vm.getHostId() != null) {
collectVmDiskStatistics(vm);
return _itMgr.reboot(vm, null, caller, owner);
} else {
s_logger.error("Vm id=" + vmId
@ -3379,9 +3380,6 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
boolean status;
State vmState = vm.getState();
// Collect vm disk statistics from host before stopping Vm
collectVmDiskStatistics(vm);
try {
VirtualMachineEntity vmEntity = _orchSrvc.getVirtualMachine(vm.getUuid());
status = vmEntity.destroy(new Long(userId).toString());
@ -3830,7 +3828,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
"No permission to migrate VM, Only Root Admin can migrate a VM!");
}
VMInstanceVO vm = _vmInstanceDao.findById(vmId);
UserVmVO vm = _vmDao.findById(vmId);
if (vm == null) {
throw new InvalidParameterValueException(
"Unable to find the VM by id=" + vmId);
@ -3921,6 +3919,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
+ " already has max Running VMs(count includes system VMs), cannot migrate to this host");
}
collectVmDiskStatistics(vm);
VMInstanceVO migratedVm = _itMgr.migrate(vm, srcHostId, dest);
return migratedVm;
}
@ -4710,6 +4709,9 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use
@Override
public void prepareStop(VirtualMachineProfile<UserVmVO> profile) {
UserVmVO vm = profile.getVirtualMachine();
if (vm.getState() == State.Running)
collectVmDiskStatistics(vm);
}
}

View File

@ -25,228 +25,163 @@ from marvin.integration.lib.common import *
from nose.plugins.attrib import attr
class Services:
def __init__(self):
self.services = {
"account": {
"email": "test@test.com",
"firstname": "Test",
"lastname": "User",
"username": "test",
"password": "password",
},
"virtual_machine": {
"displayname": "Test VM",
"username": "root",
"password": "password",
"ssh_port": 22,
"hypervisor": 'XenServer',
"privateport": 22,
"publicport": 22,
"protocol": 'TCP',
},
"ostype": 'CentOS 5.3 (64-bit)',
"service_offering": {
"name": "Tiny Instance",
"displaytext": "Tiny Instance",
"cpunumber": 1,
"cpuspeed": 100,
"memory": 256,
},
"network_offering": {
"name": "Network offering for internal lb service",
"displaytext": "Network offering for internal lb service",
"guestiptype": "Isolated",
"traffictype": "Guest",
"supportedservices": "Vpn,Dhcp,Dns,Lb,UserData,SourceNat,StaticNat,PortForwarding,NetworkACL",
"serviceProviderList": {
"Dhcp": "VpcVirtualRouter",
"Dns": "VpcVirtualRouter",
"Vpn": "VpcVirtualRouter",
"UserData": "VpcVirtualRouter",
"Lb": "InternalLbVM",
"SourceNat": "VpcVirtualRouter",
"StaticNat": "VpcVirtualRouter",
"PortForwarding": "VpcVirtualRouter",
"NetworkACL": "VpcVirtualRouter",
},
"serviceCapabilityList": {
"SourceNat": {"SupportedSourceNatTypes": "peraccount"},
"Lb": {"lbSchemes": "internal", "SupportedLbIsolation": "dedicated"}
}
}
}
class TestInternalLb(cloudstackTestCase):
networkOfferingId = None
networkId = None
vmId = None
lbId = None
"""Test Internal LB
"""
zoneId = 1
serviceOfferingId = 1
templateId = 5
@classmethod
def setUpClass(cls):
cls.apiclient = super(TestInternalLb, cls).getClsTestClient().getApiClient()
cls.services = Services().services
cls.zone = get_zone(cls.apiclient, cls.services)
cls.domain = get_domain(cls.apiclient)
cls.service_offering = ServiceOffering.create(
cls.apiclient,
cls.services["service_offering"]
)
cls.account = Account.create(cls.apiclient, services=cls.services["account"])
cls.template = get_template(
cls.apiclient,
cls.zone.id,
cls.services["ostype"]
)
cls.debug("Successfully created account: %s, id: \
%s" % (cls.account.name,\
cls.account.id))
cls.cleanup = [cls.account]
serviceProviderList = [
{
"provider": "VpcVirtualRouter",
"service": "Vpn"
},
{
"provider": "VpcVirtualRouter",
"service": "UserData"
},
{
"provider": "VpcVirtualRouter",
"service": "Dhcp"
},
{
"provider": "VpcVirtualRouter",
"service": "Dns"
},
{
"provider": "InternalLbVM",
"service": "Lb"
},
{
"provider": "VpcVirtualRouter",
"service": "SourceNat"
},
{
"provider": "VpcVirtualRouter",
"service": "StaticNat"
},
{
"provider": "VpcVirtualRouter",
"service": "PortForwarding"
},
{
"provider": "VpcVirtualRouter",
"service": "NetworkACL"
}
]
serviceCapsList = [
{
"service": "SourceNat",
"capabilitytype": "SupportedSourceNatTypes",
"capabilityvalue": "peraccount"
},
{
"service": "Lb",
"capabilitytype": "SupportedLbIsolation",
"capabilityvalue": "dedicated"
},
{
"service": "Lb",
"capabilitytype": "lbSchemes",
"capabilityvalue": "internal"
}
]
def setUp(self):
self.apiClient = self.testClient.getApiClient()
@attr(tags=["advanced"])
@attr(tags=["smoke", "advanced"])
def test_internallb(self):
"""Test create, delete, assign, remove of internal loadbalancer
"""
#1) Create and enable network offering with Internal Lb vm service
self.createNetworkOffering()
self.networkOffering = NetworkOffering.create(self.apiclient, self.services["network_offering"], conservemode=False)
self.networkOffering.update(self.apiclient, state="Enabled")
#2) Create VPC and network in it
self.createNetwork()
#3) Deploy a vm
self.deployVm()
vpcOffering = VpcOffering.list(self.apiclient)
self.assert_(vpcOffering is not None and len(vpcOffering)>0, "No VPC offerings found")
self.services["vpc"] = {}
self.services["vpc"]["name"] = "vpc-internallb"
self.services["vpc"]["displaytext"] = "vpc-internallb"
self.services["vpc"]["cidr"] = "10.1.1.0/24"
vpc = VPC.create(
apiclient=self.apiclient,
services=self.services["vpc"],
networkDomain="vpc.internallb",
vpcofferingid=vpcOffering[0].id,
zoneid=self.zone.id,
account=self.account.name,
domainid=self.domain.id
)
self.assert_(vpc is not None, "VPC creation failed")
self.services["vpcnetwork"] = {}
self.services["vpcnetwork"]["name"] = "vpcntwk"
self.services["vpcnetwork"]["displaytext"] = "vpcntwk"
ntwk = Network.create(
apiclient=self.apiclient,
services=self.services["vpcnetwork"],
accountid=self.account.name,
domainid=self.domain.id,
networkofferingid=self.networkOffering.id,
zoneid=self.zone.id,
vpcid=vpc.id,
gateway="10.1.1.1",
netmask="255.255.255.192"
)
self.assertIsNotNone(ntwk, "Network failed to create")
self.debug("Network %s created in VPC %s" %(ntwk.id, vpc.id))
#3) Deploy a vm
self.services["virtual_machine"]["networkids"] = ntwk.id
vm = VirtualMachine.create(self.apiclient, services=self.services["virtual_machine"],
templateid=self.template.id,
zoneid=self.zone.id,
accountid=self.account.name,
domainid= self.domain.id,
serviceofferingid=self.service_offering.id,
)
self.assert_(vm is not None, "VM failed to deploy")
self.assert_(vm.state == 'Running', "VM is not running")
self.debug("VM %s deployed in VPC %s" %(vm.id, vpc.id))
#4) Create an Internal Load Balancer
self.createInternalLoadBalancer()
applb = ApplicationLoadBalancer.create(self.apiclient, services=self.services,
name="lbrule",
sourceport=22,
instanceport=22,
algorithm="roundrobin",
scheme="internal",
sourcenetworkid=ntwk.id,
networkid=ntwk.id)
#5) Assign the VM to the Internal Load Balancer
self.assignToLoadBalancerRule()
applb.assign(self.apiclient, vms=[vm.id])
#6) Remove the vm from the Interanl Load Balancer
self.removeFromLoadBalancerRule()
applb.remove(self.apiclient, vms=[vm.id])
#7) Delete the Load Balancer
self.deleteLoadBalancer()
applb.delete(self.apiclient)
@classmethod
def tearDownClass(cls):
try:
cleanup_resources(cls.apiclient, cls.cleanup)
except Exception, e:
raise Exception("Cleanup failed with %s" % e)
def deployVm(self):
deployVirtualMachineCmd = deployVirtualMachine.deployVirtualMachineCmd()
deployVirtualMachineCmd.networkids = TestInternalLb.networkId
deployVirtualMachineCmd.serviceofferingid = TestInternalLb.serviceOfferingId
deployVirtualMachineCmd.zoneid = TestInternalLb.zoneId
deployVirtualMachineCmd.templateid = TestInternalLb.templateId
deployVirtualMachineCmd.hypervisor = "XenServer"
deployVMResponse = self.apiClient.deployVirtualMachine(deployVirtualMachineCmd)
TestInternalLb.vmId = deployVMResponse.id
def createInternalLoadBalancer(self):
createLoadBalancerCmd = createLoadBalancer.createLoadBalancerCmd()
createLoadBalancerCmd.name = "lb rule"
createLoadBalancerCmd.sourceport = 22
createLoadBalancerCmd.instanceport = 22
createLoadBalancerCmd.algorithm = "roundrobin"
createLoadBalancerCmd.scheme = "internal"
createLoadBalancerCmd.sourceipaddressnetworkid = TestInternalLb.networkId
createLoadBalancerCmd.networkid = TestInternalLb.networkId
createLoadBalancerResponse = self.apiClient.createLoadBalancer(createLoadBalancerCmd)
TestInternalLb.lbId = createLoadBalancerResponse.id
self.assertIsNotNone(createLoadBalancerResponse.id, "Failed to create a load balancer")
def assignToLoadBalancerRule(self):
assignToLoadBalancerRuleCmd = assignToLoadBalancerRule.assignToLoadBalancerRuleCmd()
assignToLoadBalancerRuleCmd.id = TestInternalLb.lbId
assignToLoadBalancerRuleCmd.virtualMachineIds = TestInternalLb.vmId
assignToLoadBalancerRuleResponse = self.apiClient.assignToLoadBalancerRule(assignToLoadBalancerRuleCmd)
self.assertTrue(assignToLoadBalancerRuleResponse.success, "Failed to assign the vm to the load balancer")
def removeFromLoadBalancerRule(self):
removeFromLoadBalancerRuleCmd = removeFromLoadBalancerRule.removeFromLoadBalancerRuleCmd()
removeFromLoadBalancerRuleCmd.id = TestInternalLb.lbId
removeFromLoadBalancerRuleCmd.virtualMachineIds = TestInternalLb.vmId
removeFromLoadBalancerRuleResponse = self.apiClient.removeFromLoadBalancerRule(removeFromLoadBalancerRuleCmd)
self.assertTrue(removeFromLoadBalancerRuleResponse.success, "Failed to remove the vm from the load balancer")
#def removeInternalLoadBalancer(self):
def deleteLoadBalancer(self):
deleteLoadBalancerCmd = deleteLoadBalancer.deleteLoadBalancerCmd()
deleteLoadBalancerCmd.id = TestInternalLb.lbId
deleteLoadBalancerResponse = self.apiClient.deleteLoadBalancer(deleteLoadBalancerCmd)
self.assertTrue(deleteLoadBalancerResponse.success, "Failed to remove the load balancer")
def createNetwork(self):
createVPCCmd = createVPC.createVPCCmd()
createVPCCmd.name = "new vpc"
createVPCCmd.cidr = "10.1.1.0/24"
createVPCCmd.displaytext = "new vpc"
createVPCCmd.vpcofferingid = 1
createVPCCmd.zoneid = self.zoneId
createVPCResponse = self.apiClient.createVPC(createVPCCmd)
createNetworkCmd = createNetwork.createNetworkCmd()
createNetworkCmd.name = "vpc network"
createNetworkCmd.displaytext = "vpc network"
createNetworkCmd.netmask = "255.255.255.0"
createNetworkCmd.gateway = "10.1.1.1"
createNetworkCmd.zoneid = self.zoneId
createNetworkCmd.vpcid = createVPCResponse.id
createNetworkCmd.networkofferingid = TestInternalLb.networkOfferingId
createNetworkResponse = self.apiClient.createNetwork(createNetworkCmd)
TestInternalLb.networkId = createNetworkResponse.id
self.assertIsNotNone(createNetworkResponse.id, "Network failed to create")
def createNetworkOffering(self):
createNetworkOfferingCmd = createNetworkOffering.createNetworkOfferingCmd()
createNetworkOfferingCmd.name = "Network offering for internal lb service - " + str(random.randrange(1,100+1))
createNetworkOfferingCmd.displaytext = "Network offering for internal lb service"
createNetworkOfferingCmd.guestiptype = "isolated"
createNetworkOfferingCmd.traffictype = "Guest"
createNetworkOfferingCmd.conservemode = "false"
createNetworkOfferingCmd.supportedservices = "Vpn,Dhcp,Dns,Lb,UserData,SourceNat,StaticNat,PortForwarding,NetworkACL"
createNetworkOfferingCmd.serviceproviderlist = []
for item in self.serviceProviderList:
createNetworkOfferingCmd.serviceproviderlist.append({
'service': item['service'],
'provider': item['provider']
})
createNetworkOfferingCmd.servicecapabilitylist = []
for item in self.serviceCapsList:
createNetworkOfferingCmd.servicecapabilitylist.append({
'service': item['service'],
'capabilitytype': item['capabilitytype'],
'capabilityvalue': item['capabilityvalue']
})
createNetworkOfferingResponse = self.apiClient.createNetworkOffering(createNetworkOfferingCmd)
TestInternalLb.networkOfferingId = createNetworkOfferingResponse.id
#enable network offering
updateNetworkOfferingCmd = updateNetworkOffering.updateNetworkOfferingCmd()
updateNetworkOfferingCmd.id = TestInternalLb.networkOfferingId
updateNetworkOfferingCmd.state = "Enabled"
updateNetworkOfferingResponse = self.apiClient.updateNetworkOffering(updateNetworkOfferingCmd)
#list network offering to see if its enabled
listNetworkOfferingsCmd = listNetworkOfferings.listNetworkOfferingsCmd()
listNetworkOfferingsCmd.id = TestInternalLb.networkOfferingId
listOffResponse = self.apiClient.listNetworkOfferings(listNetworkOfferingsCmd)
self.assertNotEqual(len(listOffResponse), 0, "Check if the list network offerings API \
returns a non-empty response")
def tearDown(self):
#destroy the vm
if TestInternalLb.vmId is not None:
destroyVirtualMachineCmd = destroyVirtualMachine.destroyVirtualMachineCmd()
destroyVirtualMachineCmd.id = TestInternalLb.vmId
destroyVirtualMachineResponse = self.apiClient.destroyVirtualMachine(destroyVirtualMachineCmd)

View File

@ -485,7 +485,7 @@ class TestISO(cloudstackTestCase):
if len(self.zones) <= 1:
self.skipTest("Not enough zones available to perform copy template")
self.services["destzoneid"] = filter(lambda z: z.id != self.zone.id, self.zones)[0]
self.services["destzoneid"] = filter(lambda z: z.id != self.zone.id, self.zones)[0].id
self.debug("Copy ISO from %s to %s" % (
self.zone.id,

View File

@ -24,96 +24,154 @@ from marvin.integration.lib.base import *
from marvin.integration.lib.common import *
from nose.plugins.attrib import attr
class Services:
def __init__(self):
self.services = {
"account": {
"email": "test@test.com",
"firstname": "Test",
"lastname": "User",
"username": "test",
"password": "password",
},
"virtual_machine": {
"displayname": "Test VM",
"username": "root",
"password": "password",
"ssh_port": 22,
"hypervisor": 'XenServer',
"privateport": 22,
"publicport": 22,
"protocol": 'TCP',
},
"ostype": 'CentOS 5.3 (64-bit)',
"service_offering": {
"name": "Tiny Instance",
"displaytext": "Tiny Instance",
"cpunumber": 1,
"cpuspeed": 100,
"memory": 256,
},
"network_offering": {
"name": "Network offering for internal lb service",
"displaytext": "Network offering for internal lb service",
"guestiptype": "Isolated",
"traffictype": "Guest",
"supportedservices": "Vpn,Dhcp,Dns,Lb,UserData,SourceNat,StaticNat,PortForwarding,NetworkACL",
"serviceProviderList": {
"Dhcp": "VpcVirtualRouter",
"Dns": "VpcVirtualRouter",
"Vpn": "VpcVirtualRouter",
"UserData": "VpcVirtualRouter",
"Lb": "InternalLbVM",
"SourceNat": "VpcVirtualRouter",
"StaticNat": "VpcVirtualRouter",
"PortForwarding": "VpcVirtualRouter",
"NetworkACL": "VpcVirtualRouter",
},
"serviceCapabilityList": {
"SourceNat": {"SupportedSourceNatTypes": "peraccount"},
"Lb": {"lbSchemes": "internal", "SupportedLbIsolation": "dedicated"}
}
}
}
class TestNetworkACL(cloudstackTestCase):
networkOfferingId = 11
networkId = None
vmId = None
vpcId = None
aclId = None
zoneId = 1
serviceOfferingId = 1
templateId = 5
@classmethod
def setUpClass(cls):
cls.apiclient = super(TestNetworkACL, cls).getClsTestClient().getApiClient()
cls.services = Services().services
cls.zone = get_zone(cls.apiclient, cls.services)
cls.domain = get_domain(cls.apiclient)
cls.service_offering = ServiceOffering.create(
cls.apiclient,
cls.services["service_offering"]
)
cls.account = Account.create(cls.apiclient, services=cls.services["account"])
cls.template = get_template(
cls.apiclient,
cls.zone.id,
cls.services["ostype"]
)
cls.debug("Successfully created account: %s, id: \
%s" % (cls.account.name,\
cls.account.id))
cls.cleanup = [cls.account]
def setUp(self):
self.apiClient = self.testClient.getApiClient()
@attr(tags=["advanced"])
def test_networkAcl(self):
def test_network_acl(self):
"""Test network ACL lists and items in VPC"""
# 0) Get the default network offering for VPC
networkOffering = NetworkOffering.list(self.apiclient, name="DefaultIsolatedNetworkOfferingForVpcNetworks")
self.assert_(networkOffering is not None and len(networkOffering) > 0, "No VPC based network offering")
# 1) Create VPC
self.createVPC()
vpcOffering = VpcOffering.list(self.apiclient)
self.assert_(vpcOffering is not None and len(vpcOffering)>0, "No VPC offerings found")
self.services["vpc"] = {}
self.services["vpc"]["name"] = "vpc-networkacl"
self.services["vpc"]["displaytext"] = "vpc-networkacl"
self.services["vpc"]["cidr"] = "10.1.1.0/24"
vpc = VPC.create(
apiclient=self.apiclient,
services=self.services["vpc"],
networkDomain="vpc.networkacl",
vpcofferingid=vpcOffering[0].id,
zoneid=self.zone.id,
account=self.account.name,
domainid=self.domain.id
)
self.assert_(vpc is not None, "VPC creation failed")
# 2) Create ACl
self.createACL()
# 2) Create ACL
aclgroup = NetworkACLList.create(apiclient=self.apiclient, services={}, name="acl", description="acl", vpcid=vpc.id)
self.assertIsNotNone(aclgroup, "Failed to create NetworkACL list")
self.debug("Created a network ACL list %s" % aclgroup.name)
# 3) Create ACl Item
self.createACLItem()
# 3) Create ACL Item
aclitem = NetworkACL.create(apiclient=self.apiclient, services={},
protocol="TCP", number="10", action="Deny", aclid=aclgroup.id, cidrlist=["0.0.0.0/0"])
self.assertIsNotNone(aclitem, "Network failed to aclItem")
self.debug("Added a network ACL %s to ACL list %s" % (aclitem.id, aclgroup.name))
# 4) Create network with ACL
self.createNetwork()
self.services["vpcnetwork"] = {}
self.services["vpcnetwork"]["name"] = "vpcntwk"
self.services["vpcnetwork"]["displaytext"] = "vpcntwk"
ntwk = Network.create(
apiclient=self.apiclient,
services=self.services["vpcnetwork"],
accountid=self.account.name,
domainid=self.domain.id,
networkofferingid=networkOffering[0].id,
zoneid=self.zone.id,
vpcid=vpc.id,
aclid=aclgroup.id,
gateway="10.1.1.1",
netmask="255.255.255.192"
)
self.assertIsNotNone(ntwk, "Network failed to create")
self.debug("Network %s created in VPC %s" %(ntwk.id, vpc.id))
# 5) Deploy a vm
self.deployVm()
self.services["virtual_machine"]["networkids"] = ntwk.id
vm = VirtualMachine.create(self.apiclient, services=self.services["virtual_machine"],
templateid=self.template.id,
zoneid=self.zone.id,
accountid=self.account.name,
domainid= self.domain.id,
serviceofferingid=self.service_offering.id,
)
self.assert_(vm is not None, "VM failed to deploy")
self.assert_(vm.state == 'Running', "VM is not running")
self.debug("VM %s deployed in VPC %s" %(vm.id, vpc.id))
def createACL(self):
createAclCmd = createNetworkACLList.createNetworkACLListCmd()
createAclCmd.name = "acl1"
createAclCmd.description = "new acl"
createAclCmd.vpcId = TestNetworkACL.vpcId
createAclResponse = self.apiClient.createNetworkACLList(createAclCmd)
TestNetworkACL.aclId = createAclResponse.id
def createACLItem(self):
createAclItemCmd = createNetworkACL.createNetworkACLCmd()
createAclItemCmd.cidr = "0.0.0.0/0"
createAclItemCmd.protocol = "TCP"
createAclItemCmd.number = "10"
createAclItemCmd.action = "Deny"
createAclItemCmd.aclId = TestNetworkACL.aclId
createAclItemResponse = self.apiClient.createNetworkACL(createAclItemCmd)
self.assertIsNotNone(createAclItemResponse.id, "Network failed to aclItem")
def createVPC(self):
createVPCCmd = createVPC.createVPCCmd()
createVPCCmd.name = "new vpc"
createVPCCmd.cidr = "10.1.1.0/24"
createVPCCmd.displaytext = "new vpc"
createVPCCmd.vpcofferingid = 1
createVPCCmd.zoneid = self.zoneId
createVPCResponse = self.apiClient.createVPC(createVPCCmd)
TestNetworkACL.vpcId = createVPCResponse.id
def createNetwork(self):
createNetworkCmd = createNetwork.createNetworkCmd()
createNetworkCmd.name = "vpc network"
createNetworkCmd.displaytext = "vpc network"
createNetworkCmd.netmask = "255.255.255.0"
createNetworkCmd.gateway = "10.1.1.1"
createNetworkCmd.zoneid = self.zoneId
createNetworkCmd.vpcid = TestNetworkACL.vpcId
createNetworkCmd.networkofferingid = TestNetworkACL.networkOfferingId
createNetworkCmd.aclId = TestNetworkACL.aclId
createNetworkResponse = self.apiClient.createNetwork(createNetworkCmd)
TestNetworkACL.networkId = createNetworkResponse.id
self.assertIsNotNone(createNetworkResponse.id, "Network failed to create")
def deployVm(self):
deployVirtualMachineCmd = deployVirtualMachine.deployVirtualMachineCmd()
deployVirtualMachineCmd.networkids = TestNetworkACL.networkId
deployVirtualMachineCmd.serviceofferingid = TestNetworkACL.serviceOfferingId
deployVirtualMachineCmd.zoneid = TestNetworkACL.zoneId
deployVirtualMachineCmd.templateid = TestNetworkACL.templateId
deployVirtualMachineCmd.hypervisor = "XenServer"
deployVMResponse = self.apiClient.deployVirtualMachine(deployVirtualMachineCmd)
TestNetworkACL.vmId = deployVMResponse.id
def tearDown(self):
#destroy the vm
if TestNetworkACL.vmId is not None:
destroyVirtualMachineCmd = destroyVirtualMachine.destroyVirtualMachineCmd()
destroyVirtualMachineCmd.id = TestNetworkACL.vmId
destroyVirtualMachineResponse = self.apiClient.destroyVirtualMachine(destroyVirtualMachineCmd)
@classmethod
def tearDownClass(cls):
try:
cleanup_resources(cls.apiclient, cls.cleanup)
except Exception, e:
raise Exception("Cleanup failed with %s" % e)

View File

@ -34,6 +34,15 @@ class Services:
def __init__(self):
self.services = {
"account": {
"email": "test@test.com",
"firstname": "Test",
"lastname": "User",
"username": "test",
# Random characters are appended in create account to
# ensure unique username generated each time
"password": "password",
},
"off":
{
"name": "Service Offering",

View File

@ -665,7 +665,7 @@ class TestTemplates(cloudstackTestCase):
if len(self.zones) <= 1:
self.skipTest("Not enough zones available to perform copy template")
self.services["destzoneid"] = filter(lambda z: z.id != self.services["sourcezoneid"], self.zones)[0]
self.services["destzoneid"] = filter(lambda z: z.id != self.services["sourcezoneid"], self.zones)[0].id
self.debug("Copy template from Zone: %s to %s" % (
self.services["sourcezoneid"],

View File

@ -1371,18 +1371,18 @@ class NetworkOffering:
if "useVpc" in services:
cmd.useVpc = services["useVpc"]
cmd.serviceProviderList = []
cmd.serviceproviderlist = []
if "serviceProviderList" in services:
for service, provider in services["serviceProviderList"].items():
cmd.serviceProviderList.append({
cmd.serviceproviderlist.append({
'service': service,
'provider': provider
})
if "servicecapabilitylist" in services:
cmd.serviceCapabilityList = []
for service, capability in services["servicecapabilitylist"].items():
if "serviceCapabilityList" in services:
cmd.servicecapabilitylist = []
for service, capability in services["serviceCapabilityList"].items():
for ctype, value in capability.items():
cmd.serviceCapabilityList.append({
cmd.servicecapabilitylist.append({
'service': service,
'capabilitytype': ctype,
'capabilityvalue': value
@ -1800,7 +1800,7 @@ class Network:
def create(cls, apiclient, services, accountid=None, domainid=None,
networkofferingid=None, projectid=None,
subdomainaccess=None, zoneid=None,
gateway=None, netmask=None, vpcid=None, guestcidr=None):
gateway=None, netmask=None, vpcid=None, aclid=None, guestcidr=None):
"""Create Network for account"""
cmd = createNetwork.createNetworkCmd()
cmd.name = services["name"]
@ -1846,6 +1846,8 @@ class Network:
cmd.guestcidr = guestcidr
if vpcid:
cmd.vpcid = vpcid
if aclid:
cmd.aclid = aclid
return Network(apiclient.createNetwork(cmd).__dict__)
def delete(self, apiclient):
@ -1888,25 +1890,55 @@ class NetworkACL:
self.__dict__.update(items)
@classmethod
def create(cls, apiclient, networkid, services, traffictype=None):
def create(cls, apiclient, services, networkid=None, protocol=None,
number=None, aclid=None, action='Allow', traffictype=None, cidrlist=[]):
"""Create network ACL rules(Ingress/Egress)"""
cmd = createNetworkACL.createNetworkACLCmd()
cmd.networkid = networkid
if "networkid" in services:
cmd.networkid = services["networkid"]
elif networkid:
cmd.networkid = networkid
if "protocol" in services:
cmd.protocol = services["protocol"]
if services["protocol"] == 'ICMP':
cmd.icmptype = -1
cmd.icmpcode = -1
elif protocol:
cmd.protocol = protocol
if services["protocol"] == 'ICMP':
cmd.icmptype = -1
cmd.icmpcode = -1
else:
if "startport" in services:
cmd.startport = services["startport"]
if "endport" in services:
cmd.endport = services["endport"]
cmd.cidrlist = services["cidrlist"]
if traffictype:
if "cidrlist" in services:
cmd.cidrlist = services["cidrlist"]
elif cidrlist:
cmd.cidrlist = cidrlist
if "traffictype" in services:
cmd.traffictype = services["traffictype"]
elif traffictype:
cmd.traffictype = traffictype
# Defaulted to Ingress
if "action" in services:
cmd.action = services["action"]
elif action:
cmd.action = action
if "number" in services:
cmd.number = services["number"]
elif number:
cmd.number = number
if "aclid" in services:
cmd.aclid = services["aclid"]
elif aclid:
cmd.aclid = aclid
# Defaulted to Ingress
return NetworkACL(apiclient.createNetworkACL(cmd).__dict__)
def delete(self, apiclient):
@ -1925,6 +1957,50 @@ class NetworkACL:
return(apiclient.listNetworkACLs(cmd))
class NetworkACLList:
"""Manage Network ACL lists lifecycle"""
def __init__(self, items):
self.__dict__.update(items)
@classmethod
def create(cls, apiclient, services, name=None, description=None, vpcid=None):
"""Create network ACL container list"""
cmd = createNetworkACLList.createNetworkACLListCmd()
if "name" in services:
cmd.name = services["name"]
elif name:
cmd.name = name
if "description" in services:
cmd.description = services["description"]
elif description:
cmd.description = description
if "vpcid" in services:
cmd.vpcid = services["vpcid"]
elif vpcid:
cmd.vpcid = vpcid
return NetworkACLList(apiclient.createNetworkACLList(cmd).__dict__)
def delete(self, apiclient):
"""Delete network acl list"""
cmd = deleteNetworkACLList.deleteNetworkACLListCmd()
cmd.id = self.id
return apiclient.deleteNetworkACLList(cmd)
@classmethod
def list(cls, apiclient, **kwargs):
"""List Network ACL lists"""
cmd = listNetworkACLLists.listNetworkACLListsCmd()
[setattr(cmd, k, v) for k, v in kwargs.items()]
return(apiclient.listNetworkACLLists(cmd))
class Vpn:
"""Manage VPN life cycle"""
@ -2798,7 +2874,7 @@ class VPC:
@classmethod
def create(cls, apiclient, services, vpcofferingid,
zoneid, networkDomain=None, account=None, domainid=None):
zoneid, networkDomain=None, account=None, domainid=None, **kwargs):
"""Creates the virtual private connection (VPC)"""
cmd = createVPC.createVPCCmd()
@ -2806,13 +2882,15 @@ class VPC:
cmd.displaytext = "-".join([services["displaytext"], random_gen()])
cmd.vpcofferingid = vpcofferingid
cmd.zoneid = zoneid
cmd.cidr = services["cidr"]
if "cidr" in services:
cmd.cidr = services["cidr"]
if account:
cmd.account = account
if domainid:
cmd.domainid = domainid
if networkDomain:
cmd.networkDomain = networkDomain
[setattr(cmd, k, v) for k, v in kwargs.items()]
return VPC(apiclient.createVPC(cmd).__dict__)
def update(self, apiclient, name=None, displaytext=None):
@ -3216,3 +3294,83 @@ class Region:
cmd.id = self.id
region = apiclient.removeRegion(cmd)
return region
class ApplicationLoadBalancer:
"""Manage Application Load Balancers in VPC"""
def __init__(self, items):
self.__dict__.update(items)
@classmethod
def create(cls, apiclient, services, name=None, sourceport=None, instanceport=22,
algorithm="roundrobin", scheme="internal", sourcenetworkid=None, networkid=None):
"""Create Application Load Balancer"""
cmd = createLoadBalancer.createLoadBalancerCmd()
if "name" in services:
cmd.name = services["name"]
elif name:
cmd.name = name
if "sourceport" in services:
cmd.sourceport = services["sourceport"]
elif sourceport:
cmd.sourceport = sourceport
if "instanceport" in services:
cmd.instanceport = services["instanceport"]
elif instanceport:
cmd.instanceport = instanceport
if "algorithm" in services:
cmd.algorithm = services["algorithm"]
elif algorithm:
cmd.algorithm = algorithm
if "scheme" in services:
cmd.scheme = services["scheme"]
elif scheme:
cmd.scheme = scheme
if "sourceipaddressnetworkid" in services:
cmd.sourceipaddressnetworkid = services["sourceipaddressnetworkid"]
elif sourcenetworkid:
cmd.sourceipaddressnetworkid = sourcenetworkid
if "networkid" in services:
cmd.networkid = services["networkid"]
elif networkid:
cmd.networkid = networkid
return LoadBalancerRule(apiclient.createLoadBalancer(cmd).__dict__)
def delete(self, apiclient):
"""Delete application load balancer"""
cmd = deleteLoadBalancer.deleteLoadBalancerCmd()
cmd.id = self.id
apiclient.deleteLoadBalancerRule(cmd)
return
def assign(self, apiclient, vms):
"""Assign virtual machines to load balancing rule"""
cmd = assignToLoadBalancerRule.assignToLoadBalancerRuleCmd()
cmd.id = self.id
cmd.virtualmachineids = [str(vm.id) for vm in vms]
apiclient.assignToLoadBalancerRule(cmd)
return
def remove(self, apiclient, vms):
"""Remove virtual machines from load balancing rule"""
cmd = removeFromLoadBalancerRule.removeFromLoadBalancerRuleCmd()
cmd.id = self.id
cmd.virtualmachineids = [str(vm.id) for vm in vms]
apiclient.removeFromLoadBalancerRule(cmd)
return
@classmethod
def list(cls, apiclient, **kwargs):
"""List all appln load balancers"""
cmd = listLoadBalancers.listLoadBalancersCmd()
[setattr(cmd, k, v) for k, v in kwargs.items()]
return(apiclient.listLoadBalancerRules(cmd))

View File

@ -849,6 +849,9 @@
getUpdatedItem: function(data) {
return $.extend(data, { state: 'Destroyed' });
},
onComplete: function(data) {
$(window).trigger('cloudStack.deleteProject', args);
},
getActionFilter: function(args) {
return function() {
return [];

View File

@ -333,9 +333,15 @@
response: {
success: function(args) {
var project = args.data;
var $projectSwitcher = $('div.project-switcher');
$(window).trigger('cloudStack.fullRefresh');
// dynamically add newly created project into project switcher
$projectSwitcher.find('select').append(
$('<option>').val(project.id).html(project.name)
);
$loading.remove();
// Confirmation
@ -681,6 +687,20 @@
}).closest('.ui-dialog').overlay();
};
var deleteProject = function(args) {
var projectId = args.id;
var $projectSwitcher = $('div.project-switcher');
var contextProjectId = cloudStack.context.projects ? cloudStack.context.projects[0].id : -1;
$projectSwitcher.find('option[value="'+projectId+'"]').remove();
//return to default view if current project is deleted
if(contextProjectId == projectId) {
$projectSwitcher.find('select').trigger('change');
}
return false;
};
/**
* Show the dashboard, in panel
*/
@ -741,4 +761,9 @@
$(window).bind('cloudStack.newProject', function() {
addProject();
});
$(window).bind('cloudStack.deleteProject', function(event, args) {
deleteProject({id: args.data.id});
});
})(cloudStack, jQuery);