diff --git a/docs/en-US/CloudStack_GSoC_Guide.ent b/docs/en-US/CloudStack_GSoC_Guide.ent new file mode 100644 index 00000000000..17415873334 --- /dev/null +++ b/docs/en-US/CloudStack_GSoC_Guide.ent @@ -0,0 +1,22 @@ + + + + + + diff --git a/docs/en-US/CloudStack_GSoC_Guide.xml b/docs/en-US/CloudStack_GSoC_Guide.xml new file mode 100644 index 00000000000..91c2967fc45 --- /dev/null +++ b/docs/en-US/CloudStack_GSoC_Guide.xml @@ -0,0 +1,52 @@ + + +%BOOK_ENTITIES; + +%xinclude; +]> + + + + + + &PRODUCT; Guide for the 2013 Google Summer of Code + Apache CloudStack + 4.3.0 + 1 + + + + Guide for 2013 Google Summer of Code Projects. + + + + + + + + + + + + + + + + diff --git a/docs/en-US/gsoc-tuna.xml b/docs/en-US/gsoc-tuna.xml new file mode 100644 index 00000000000..68032a8d46d --- /dev/null +++ b/docs/en-US/gsoc-tuna.xml @@ -0,0 +1,28 @@ + + +%BOOK_ENTITIES; +]> + + + + + Nguyen's 2013 GSoC Proposal + This chapter describes Nguyen 2013 Google Summer of Code project within the &PRODUCT; ASF project. It is a copy paste of the submitted proposal. + diff --git a/docs/en-US/multiple-ip-range.xml b/docs/en-US/multiple-ip-range.xml index a8d68c00911..42e0c2a9555 100644 --- a/docs/en-US/multiple-ip-range.xml +++ b/docs/en-US/multiple-ip-range.xml @@ -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 createVlanIpRange API is extended to add IP ranges also from a different subnet. Ensure that you manually configure the gateway of the new subnet before adding the IP range. diff --git a/docs/en-US/pvlan.xml b/docs/en-US/pvlan.xml new file mode 100644 index 00000000000..96c1a78a85d --- /dev/null +++ b/docs/en-US/pvlan.xml @@ -0,0 +1,57 @@ + + +%BOOK_ENTITIES; +]> + + +
+ Isolation in Advanced Zone Using Private VLAN + +
+ About Private VLAN + 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. + For further reading: + + + Understanding Private VLANs + + + Cisco Systems' Private VLANs: Scalable + Security in a Multi-Client Environment + + + Private VLAN (PVLAN) on vNetwork Distributed Switch + - Concept Overview (1010691) + + +
+
+ Prerequisites + Ensure that you configure private VLAN on your physical switches out-of-band. +
+
diff --git a/docs/publican-gsoc-2013.cfg b/docs/publican-gsoc-2013.cfg new file mode 100644 index 00000000000..35dc517be12 --- /dev/null +++ b/docs/publican-gsoc-2013.cfg @@ -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 diff --git a/engine/schema/src/com/cloud/vm/dao/UserVmDao.java b/engine/schema/src/com/cloud/vm/dao/UserVmDao.java index e7cd61bddfe..b4f9991c99b 100755 --- a/engine/schema/src/com/cloud/vm/dao/UserVmDao.java +++ b/engine/schema/src/com/cloud/vm/dao/UserVmDao.java @@ -54,10 +54,9 @@ public interface UserVmDao extends GenericDao { /** * 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 listVirtualNetworkInstancesByAcctAndZone(long accountId, long dcId, long networkId); + List listVirtualNetworkInstancesByAcctAndNetwork(long accountId, long networkId); List listByNetworkIdAndStates(long networkId, State... states); diff --git a/engine/schema/src/com/cloud/vm/dao/UserVmDaoImpl.java b/engine/schema/src/com/cloud/vm/dao/UserVmDaoImpl.java index 5e8be1054a9..1c11563b270 100755 --- a/engine/schema/src/com/cloud/vm/dao/UserVmDaoImpl.java +++ b/engine/schema/src/com/cloud/vm/dao/UserVmDaoImpl.java @@ -283,11 +283,10 @@ public class UserVmDaoImpl extends GenericDaoBase implements Use } @Override - public List listVirtualNetworkInstancesByAcctAndZone(long accountId, long dcId, long networkId) { + public List listVirtualNetworkInstancesByAcctAndNetwork(long accountId, long networkId) { SearchCriteria sc = AccountDataCenterVirtualSearch.create(); sc.setParameters("account", accountId); - sc.setParameters("dc", dcId); sc.setJoinParameters("nicSearch", "networkId", networkId); return listBy(sc); diff --git a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java index d52859bd4c0..67d31ab3a4e 100755 --- a/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java +++ b/server/src/com/cloud/network/lb/LoadBalancingRulesManagerImpl.java @@ -1835,9 +1835,8 @@ public class LoadBalancingRulesManagerImpl extends ManagerBase implements } } - IPAddressVO addr = _ipAddressDao.findById(loadBalancer.getSourceIpAddressId()); - List userVms = _vmDao.listVirtualNetworkInstancesByAcctAndZone(loadBalancer.getAccountId(), - addr.getDataCenterId(), loadBalancer.getNetworkId()); + List userVms = _vmDao.listVirtualNetworkInstancesByAcctAndNetwork(loadBalancer.getAccountId(), + loadBalancer.getNetworkId()); for (UserVmVO userVm : userVms) { // if the VM is destroyed, being expunged, in an error state, or in diff --git a/server/src/com/cloud/vm/UserVmManagerImpl.java b/server/src/com/cloud/vm/UserVmManagerImpl.java index d8a064f5987..b919f124b1b 100755 --- a/server/src/com/cloud/vm/UserVmManagerImpl.java +++ b/server/src/com/cloud/vm/UserVmManagerImpl.java @@ -4709,7 +4709,7 @@ public class UserVmManagerImpl extends ManagerBase implements UserVmManager, Use @Override public void prepareStop(VirtualMachineProfile profile) { - UserVmVO vm = profile.getVirtualMachine(); + UserVmVO vm = _vmDao.findById(profile.getId()); if (vm.getState() == State.Running) collectVmDiskStatistics(vm); } diff --git a/test/integration/smoke/test_internal_lb.py b/test/integration/smoke/test_internal_lb.py index 0de2d4cf338..0535d6a5345 100644 --- a/test/integration/smoke/test_internal_lb.py +++ b/test/integration/smoke/test_internal_lb.py @@ -170,10 +170,10 @@ class TestInternalLb(cloudstackTestCase): networkid=ntwk.id) #5) Assign the VM to the Internal Load Balancer - applb.assign(self.apiclient, vms=[vm.id]) + applb.assign(self.apiclient, vms=[vm]) #6) Remove the vm from the Interanl Load Balancer - applb.remove(self.apiclient, vms=[vm.id]) + applb.remove(self.apiclient, vms=[vm]) #7) Delete the Load Balancer applb.delete(self.apiclient) diff --git a/test/integration/smoke/test_iso.py b/test/integration/smoke/test_iso.py index c645d3b055d..75289b8fbe3 100644 --- a/test/integration/smoke/test_iso.py +++ b/test/integration/smoke/test_iso.py @@ -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, diff --git a/test/integration/smoke/test_network_acl.py b/test/integration/smoke/test_network_acl.py index 3ed45be9cd0..4b3c1f70b67 100644 --- a/test/integration/smoke/test_network_acl.py +++ b/test/integration/smoke/test_network_acl.py @@ -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) diff --git a/test/integration/smoke/test_service_offerings.py b/test/integration/smoke/test_service_offerings.py index 3d3b94684e8..a56e34d2874 100644 --- a/test/integration/smoke/test_service_offerings.py +++ b/test/integration/smoke/test_service_offerings.py @@ -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", diff --git a/test/integration/smoke/test_templates.py b/test/integration/smoke/test_templates.py index 8b83f5e6e43..9478440f77e 100644 --- a/test/integration/smoke/test_templates.py +++ b/test/integration/smoke/test_templates.py @@ -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"], diff --git a/tools/appliance/definitions/systemvmtemplate/postinstall.sh b/tools/appliance/definitions/systemvmtemplate/postinstall.sh index 7c067962700..e052cf9c1c3 100644 --- a/tools/appliance/definitions/systemvmtemplate/postinstall.sh +++ b/tools/appliance/definitions/systemvmtemplate/postinstall.sh @@ -113,7 +113,7 @@ fix_nameserver() { # Replace /etc/resolv.conf also cat > /etc/resolv.conf << EOF nameserver 8.8.8.8 -nameserver 4.4.4.4 +nameserver 8.8.4.4 EOF } diff --git a/tools/appliance/definitions/systemvmtemplate64/postinstall.sh b/tools/appliance/definitions/systemvmtemplate64/postinstall.sh index 35a4e4ac72d..786d38d4ef0 100644 --- a/tools/appliance/definitions/systemvmtemplate64/postinstall.sh +++ b/tools/appliance/definitions/systemvmtemplate64/postinstall.sh @@ -112,7 +112,7 @@ fix_nameserver() { # Replace /etc/resolv.conf also cat > /etc/resolv.conf << EOF nameserver 8.8.8.8 -nameserver 4.4.4.4 +nameserver 8.8.4.4 EOF } diff --git a/tools/devcloud-kvm/devcloud-kvm.cfg b/tools/devcloud-kvm/devcloud-kvm.cfg index b3f048aac97..9f310e32755 100644 --- a/tools/devcloud-kvm/devcloud-kvm.cfg +++ b/tools/devcloud-kvm/devcloud-kvm.cfg @@ -46,7 +46,7 @@ ] } ], - "dns2": "4.4.4.4", + "dns2": "8.8.4.4", "dns1": "8.8.8.8", "securitygroupenabled": "true", "localstorageenabled": "true", diff --git a/tools/devcloud/devcloud.cfg b/tools/devcloud/devcloud.cfg index e6ab71b5ebf..f665e82c4c9 100644 --- a/tools/devcloud/devcloud.cfg +++ b/tools/devcloud/devcloud.cfg @@ -45,7 +45,7 @@ ] } ], - "dns2": "4.4.4.4", + "dns2": "8.8.4.4", "dns1": "8.8.8.8", "securitygroupenabled": "true", "localstorageenabled": "true", diff --git a/tools/devcloud/devcloud_internal-mgt.cfg b/tools/devcloud/devcloud_internal-mgt.cfg index fe3dd1b41da..beae34547a8 100644 --- a/tools/devcloud/devcloud_internal-mgt.cfg +++ b/tools/devcloud/devcloud_internal-mgt.cfg @@ -44,7 +44,7 @@ ] } ], - "dns2": "4.4.4.4", + "dns2": "8.8.4.4", "dns1": "8.8.8.8", "securitygroupenabled": "true", "localstorageenabled": "true", diff --git a/tools/devcloud/quickcloud.cfg b/tools/devcloud/quickcloud.cfg index a2613d22bdb..77bc114f401 100644 --- a/tools/devcloud/quickcloud.cfg +++ b/tools/devcloud/quickcloud.cfg @@ -49,7 +49,7 @@ ] } ], - "dns2": "4.4.4.4", + "dns2": "8.8.4.4", "dns1": "8.8.8.8", "securitygroupenabled": "true", "localstorageenabled": "true", diff --git a/tools/marvin/marvin/configGenerator.py b/tools/marvin/marvin/configGenerator.py index c970ada850a..bd83efbc126 100644 --- a/tools/marvin/marvin/configGenerator.py +++ b/tools/marvin/marvin/configGenerator.py @@ -269,7 +269,7 @@ def describe_setup_in_basic_mode(): for l in range(1): z = zone() z.dns1 = "8.8.8.8" - z.dns2 = "4.4.4.4" + z.dns2 = "8.8.4.4" z.internaldns1 = "192.168.110.254" z.internaldns2 = "192.168.110.253" z.name = "test"+str(l) @@ -390,7 +390,7 @@ def describe_setup_in_eip_mode(): for l in range(1): z = zone() z.dns1 = "8.8.8.8" - z.dns2 = "4.4.4.4" + z.dns2 = "8.8.4.4" z.internaldns1 = "192.168.110.254" z.internaldns2 = "192.168.110.253" z.name = "test"+str(l) @@ -519,7 +519,7 @@ def describe_setup_in_advanced_mode(): for l in range(1): z = zone() z.dns1 = "8.8.8.8" - z.dns2 = "4.4.4.4" + z.dns2 = "8.8.4.4" z.internaldns1 = "192.168.110.254" z.internaldns2 = "192.168.110.253" z.name = "test"+str(l) @@ -645,7 +645,7 @@ def describe_setup_in_advancedsg_mode(): for l in range(1): z = zone() z.dns1 = "8.8.8.8" - z.dns2 = "4.4.4.4" + z.dns2 = "8.8.4.4" z.internaldns1 = "192.168.110.254" z.internaldns2 = "192.168.110.253" z.name = "test"+str(l) diff --git a/tools/marvin/marvin/integration/lib/base.py b/tools/marvin/marvin/integration/lib/base.py index 5daacbb7cea..503ed6446f5 100755 --- a/tools/marvin/marvin/integration/lib/base.py +++ b/tools/marvin/marvin/integration/lib/base.py @@ -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""" diff --git a/tools/marvin/marvin/jsonHelper.py b/tools/marvin/marvin/jsonHelper.py index 37363bc8c91..79a6369499c 100644 --- a/tools/marvin/marvin/jsonHelper.py +++ b/tools/marvin/marvin/jsonHelper.py @@ -142,7 +142,7 @@ if __name__ == "__main__": nsp = getResultObj(result) print nsp[0].id - result = '{ "listzonesresponse" : { "count":1 ,"zone" : [ {"id":1,"name":"test0","dns1":"8.8.8.8","dns2":"4.4.4.4","internaldns1":"192.168.110.254","internaldns2":"192.168.110.253","networktype":"Basic","securitygroupsenabled":true,"allocationstate":"Enabled","zonetoken":"5e818a11-6b00-3429-9a07-e27511d3169a","dhcpprovider":"DhcpServer"} ] } }' + result = '{ "listzonesresponse" : { "count":1 ,"zone" : [ {"id":1,"name":"test0","dns1":"8.8.8.8","dns2":"8.8.4.4","internaldns1":"192.168.110.254","internaldns2":"192.168.110.253","networktype":"Basic","securitygroupsenabled":true,"allocationstate":"Enabled","zonetoken":"5e818a11-6b00-3429-9a07-e27511d3169a","dhcpprovider":"DhcpServer"} ] } }' zones = getResultObj(result) print zones[0].id res = authorizeSecurityGroupIngress.authorizeSecurityGroupIngressResponse() @@ -165,7 +165,7 @@ if __name__ == "__main__": asynJob = getResultObj(result) print asynJob - result = '{ "createzoneresponse" : { "zone" : {"id":1,"name":"test0","dns1":"8.8.8.8","dns2":"4.4.4.4","internaldns1":"192.168.110.254","internaldns2":"192.168.110.253","networktype":"Basic","securitygroupsenabled":true,"allocationstate":"Enabled","zonetoken":"3442f287-e932-3111-960b-514d1f9c4610","dhcpprovider":"DhcpServer"} } }' + result = '{ "createzoneresponse" : { "zone" : {"id":1,"name":"test0","dns1":"8.8.8.8","dns2":"8.8.4.4","internaldns1":"192.168.110.254","internaldns2":"192.168.110.253","networktype":"Basic","securitygroupsenabled":true,"allocationstate":"Enabled","zonetoken":"3442f287-e932-3111-960b-514d1f9c4610","dhcpprovider":"DhcpServer"} } }' res = createZone.createZoneResponse() zone = getResultObj(result, res) print zone.id diff --git a/ui/modules/vpc/vpc.css b/ui/modules/vpc/vpc.css index db57d94c5d6..0ff99db3d59 100644 --- a/ui/modules/vpc/vpc.css +++ b/ui/modules/vpc/vpc.css @@ -154,6 +154,15 @@ cursor: pointer; } +.vpc-network-chart .tier-item .content .dashboard-item.disabled { + /*+opacity:50%;*/ + filter: alpha(opacity=50); + -ms-filter: progid:DXImageTransform.Microsoft.Alpha(Opacity=50); + -moz-opacity: 0.5; + opacity: 0.5; + cursor: not-allowed; +} + .vpc-network-chart .tier-item .content .dashboard-item:hover { background-color: #DBEDFE; /*+box-shadow:inset 0px 1px 2px #000000;*/ @@ -271,6 +280,8 @@ float: left; /*+placement:shift 10px 176px;*/ position: relative; + left: 10px; + top: 176px; left: 0px; top: 237px; } diff --git a/ui/modules/vpc/vpc.js b/ui/modules/vpc/vpc.js index 5e87dbb4fb6..981d612b520 100644 --- a/ui/modules/vpc/vpc.js +++ b/ui/modules/vpc/vpc.js @@ -231,7 +231,15 @@ $dashboardItem.append($total, $name); $dashboardItem.appendTo($dashboard); + if (dashboardItem._disabled) { + $dashboardItem.addClass('disabled'); + } + $dashboardItem.click(function() { + if ($dashboardItem.is('.disabled')) { + return false; + } + var section = cloudStack.vpc.sections[id]; var $section = $('
'); var $loading = $('
').addClass('loading-overlay'); diff --git a/ui/scripts/ui/widgets/listView.js b/ui/scripts/ui/widgets/listView.js index d68f91fac7c..ba4d2881580 100644 --- a/ui/scripts/ui/widgets/listView.js +++ b/ui/scripts/ui/widgets/listView.js @@ -25,6 +25,7 @@ var messages = args.action ? args.action.messages : {}; var preAction = args.action ? args.action.preAction : {}; var action = args.action ? args.action.action : {}; + var needsRefresh = args.action.needsRefresh; var section; var data = { id: $instanceRow.data('list-view-item-id'), @@ -142,6 +143,12 @@ $item: $instanceRow }); } else { + if (needsRefresh) { + var $loading = $('
').addClass('loading-overlay'); + + $listView.prepend($loading); + } + var actionArgs = { data: data, ref: options.ref, @@ -206,6 +213,15 @@ $instanceRow.data('json-obj'), actionFilter); } + + if (needsRefresh) { + if ($listView.closest('.detail-view').size()) { + $('.detail-view:last .button.refresh').click(); + } else { + $loading.remove(); + $listView.listView('refresh'); + } + } } if (additional && additional.complete) @@ -293,7 +309,8 @@ if (!args.action.action.externalLink && !args.action.createForm && args.action.addRow != 'true' && - !action.custom && !action.uiCustom) { + !action.custom && !action.uiCustom && + !args.action.listView) { cloudStack.dialog.confirm({ message: messages.confirm(messageArgs), action: function() { @@ -306,6 +323,14 @@ }); } else if (action.custom || action.uiCustom) { performAction(); + } else if (args.action.listView) { + cloudStack.dialog.listView({ + context: context, + listView: args.action.listView, + after: function(args) { + performAction(null, { context: args.context }); + } + }); } else { var addRow = args.action.addRow == "false" ? false : true; var isHeader = args.action.isHeader; diff --git a/ui/scripts/vpc.js b/ui/scripts/vpc.js index bc394807130..164f2bb507a 100644 --- a/ui/scripts/vpc.js +++ b/ui/scripts/vpc.js @@ -57,6 +57,13 @@ } }, fields: { + + 'rulenumber':{ + label:'Rule Number', + edit:true + + }, + 'cidrlist': { edit: true, label: 'label.cidr' }, action: { label: 'Action', @@ -442,8 +449,10 @@ }, detailView: { + isMaximized: true, name: 'Internal LB details', actions: { + /* assignVm: { label: 'Assign VMs to Internal LB', messages: { @@ -507,7 +516,8 @@ notification: { poll: pollAsyncJobResult } - }, + }, + */ remove: { label: 'Delete Internal LB', messages: { @@ -604,25 +614,161 @@ assignedVms: { title: 'Assigned VMs', - multiple: true, - fields: [ - { + listView: { + id: 'assignedVms', + fields: { name: { label: 'label.name' }, ipaddress: { label: 'label.ip.address' } - } - ], - dataProvider: function(args) { - $.ajax({ - url: createURL('listLoadBalancers'), - data: { - id: args.context.internalLoadBalancers[0].id - }, - success: function(json) { - var item = json.listloadbalancerssresponse.loadbalancer[0]; - args.response.success({ data: item.loadbalancerinstance }); + }, + dataProvider: function(args) { + $.ajax({ + url: createURL('listLoadBalancers'), + data: { + id: args.context.internalLoadBalancers[0].id + }, + success: function(json) { + var item = json.listloadbalancerssresponse.loadbalancer[0]; + args.response.success({ data: item.loadbalancerinstance }); + } + }); + }, + actions: { + add: { + label: 'Assign VMs', + messages: { + notification: function(args) { return 'Assign VMs'; } + }, + needsRefresh: true, + listView: $.extend(true, {}, cloudStack.sections.instances.listView, { + type: 'checkbox', + filters: false, + dataProvider: function(args) { + $.ajax({ + url: createURL('listVirtualMachines'), + data: { + networkid: args.context.networks[0].id, + listAll: true + }, + success: function(json) { + var instances = json.listvirtualmachinesresponse.virtualmachine; + + // Pre-select existing instances in LB rule + $(instances).map(function(index, instance) { + instance._isSelected = $.grep( + args.context.internalLoadBalancers[0].loadbalancerinstance, + + function(lbInstance) { + return lbInstance.id == instance.id; + } + ).length ? true : false; + }); + + //remove assigned VMs (i.e. instance._isSelected == true) + var items = []; + if(instances != null) { + for(var i = 0; i < instances.length; i++) { + if(instances[i]._isSelected = true) + continue; + else + items.push(instances[i]); + } + } + + args.response.success({ + data: items + }); + } + }); + } + }), + action: function(args) { + var vms = args.context.instances; + var array1 = []; + for(var i = 0; i < vms.length; i++) { + array1.push(vms[i].id); + } + var virtualmachineids = array1.join(','); + + $.ajax({ + url: createURL('assignToLoadBalancerRule'), + data: { + id: args.context.internalLoadBalancers[0].id, + virtualmachineids: virtualmachineids + }, + dataType: 'json', + async: true, + success: function(data) { + var jid = data.assigntoloadbalancerruleresponse.jobid; + args.response.success({ + _custom: { + jobId: jid, + getUpdatedItem: function(json) { + $('.list-view').listView('refresh'); + //return json.queryasyncjobresultresponse.jobresult.volume; + } + } + }); + } + }); + }, + notification: { + poll: pollAsyncJobResult + } } - }); - } + }, + detailView: { + actions: { + remove: { + label: 'remove VM from load balancer', + addRow: 'false', + messages: { + confirm: function(args) { + return 'Please confirm you want to remove VM from load balancer'; + }, + notification: function(args) { + return 'remove VM from load balancer'; + } + }, + action: function(args) { + $.ajax({ + url: createURL('removeFromLoadBalancerRule'), + data: { + id: args.context.internalLoadBalancers[0].id, + virtualmachineids: args.context.assignedVms[0].id + }, + success: function(json) { + var jid = json.removefromloadbalancerruleresponse.jobid; + args.response.success({ + _custom: { jobId: jid } + }); + } + }); + }, + notificaton: { + poll: pollAsyncJobResult + } + } + }, + tabs: { + details: { + title: 'label.details', + fields: [ + { + name: { label: 'label.name' } + }, + { + ipaddress: { label: 'label.ip.address' } + } + ], + dataProvider: function(args) { + setTimeout(function() { + args.response.success({ data: args.context.assignedVms[0] }); + }); + } + } + } + } + } } } } @@ -3177,7 +3323,8 @@ }); } - } + } + } }, action: function(args) { var dataObj = { @@ -3447,17 +3594,41 @@ } ).length ? tier._highlighted = true : tier._highlighted = false; + // Get LB capabilities + var lbSchemes = $.grep( + $.grep( + tier.service, + function(service) { + return service.name == 'Lb'; + } + )[0].capability, + function(capability) { + return capability.name == 'LbSchemes'; + } + ); + + var hasLbScheme = function(schemeVal) { + return $.grep( + lbSchemes, + function(scheme) { + return scheme.value == schemeVal; + } + ).length ? true : false; + }; + return $.extend(tier, { _dashboardItems: [ { id: 'internalLoadBalancers', name: 'Internal LB', - total: internalLoadBalancers.count + total: internalLoadBalancers.count, + _disabled: !hasLbScheme('Internal') }, { id: 'publicLbIps', name: 'Public LB IP', - total: publicLbIps.count + total: publicLbIps.count, + _disabled: !hasLbScheme('Public') }, { id: 'tierStaticNATs',