| /* |
| * Licensed to the Apache Software Foundation (ASF) under one or more |
| * contributor license agreements. See the NOTICE file distributed with |
| * this work for additional information regarding copyright ownership. |
| * The ASF licenses this file to You under the Apache License, Version 2.0 |
| * (the "License"); you may not use this file except in compliance with |
| * the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| package org.jclouds.azurecompute.arm.features; |
| |
| import static com.google.common.base.Preconditions.checkNotNull; |
| import static com.google.common.base.Preconditions.checkState; |
| import static com.google.common.collect.Iterables.any; |
| import static com.google.common.collect.Iterables.transform; |
| import static com.google.common.collect.Lists.newArrayList; |
| import static org.jclouds.azurecompute.arm.compute.options.AzureTemplateOptions.Builder.availabilitySet; |
| import static org.jclouds.azurecompute.arm.config.AzureComputeProperties.TIMEOUT_RESOURCE_DELETED; |
| import static org.jclouds.azurecompute.arm.domain.IdReference.extractName; |
| import static org.jclouds.azurecompute.arm.domain.InboundNatRuleProperties.Protocol.Tcp; |
| import static org.jclouds.compute.predicates.NodePredicates.inGroup; |
| import static org.testng.Assert.assertEquals; |
| import static org.testng.Assert.assertNotNull; |
| import static org.testng.Assert.assertNull; |
| import static org.testng.Assert.assertTrue; |
| |
| import java.net.URI; |
| import java.util.ArrayList; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Properties; |
| import java.util.Set; |
| |
| import org.jclouds.azurecompute.arm.AzureComputeApi; |
| import org.jclouds.azurecompute.arm.compute.config.AzurePredicatesModule.PublicIpAvailablePredicateFactory; |
| import org.jclouds.azurecompute.arm.compute.domain.ResourceGroupAndName; |
| import org.jclouds.azurecompute.arm.domain.AvailabilitySet; |
| import org.jclouds.azurecompute.arm.domain.AvailabilitySet.AvailabilitySetProperties; |
| import org.jclouds.azurecompute.arm.domain.BackendAddressPool; |
| import org.jclouds.azurecompute.arm.domain.BackendAddressPoolProperties; |
| import org.jclouds.azurecompute.arm.domain.FrontendIPConfigurations; |
| import org.jclouds.azurecompute.arm.domain.FrontendIPConfigurationsProperties; |
| import org.jclouds.azurecompute.arm.domain.IdReference; |
| import org.jclouds.azurecompute.arm.domain.InboundNatRule; |
| import org.jclouds.azurecompute.arm.domain.InboundNatRuleProperties; |
| import org.jclouds.azurecompute.arm.domain.IpConfiguration; |
| import org.jclouds.azurecompute.arm.domain.IpConfigurationProperties; |
| import org.jclouds.azurecompute.arm.domain.LoadBalancer; |
| import org.jclouds.azurecompute.arm.domain.LoadBalancerProperties; |
| import org.jclouds.azurecompute.arm.domain.LoadBalancingRule; |
| import org.jclouds.azurecompute.arm.domain.LoadBalancingRuleProperties; |
| import org.jclouds.azurecompute.arm.domain.LoadBalancingRuleProperties.Protocol; |
| import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCard; |
| import org.jclouds.azurecompute.arm.domain.NetworkInterfaceCardProperties; |
| import org.jclouds.azurecompute.arm.domain.Probe; |
| import org.jclouds.azurecompute.arm.domain.ProbeProperties; |
| import org.jclouds.azurecompute.arm.domain.Provisionable; |
| import org.jclouds.azurecompute.arm.domain.PublicIPAddress; |
| import org.jclouds.azurecompute.arm.domain.PublicIPAddressProperties; |
| import org.jclouds.azurecompute.arm.domain.VirtualMachine; |
| import org.jclouds.azurecompute.arm.internal.AzureLiveTestUtils; |
| import org.jclouds.compute.RunNodesException; |
| import org.jclouds.compute.domain.NodeMetadata; |
| import org.jclouds.compute.internal.BaseComputeServiceContextLiveTest; |
| import org.testng.annotations.AfterClass; |
| import org.testng.annotations.BeforeClass; |
| import org.testng.annotations.Test; |
| |
| import com.google.common.base.Function; |
| import com.google.common.base.Predicate; |
| import com.google.common.base.Supplier; |
| import com.google.common.collect.ImmutableList; |
| import com.google.common.collect.ImmutableMap; |
| import com.google.inject.Key; |
| import com.google.inject.TypeLiteral; |
| import com.google.inject.name.Names; |
| |
| // We extend the BaseComputeServiceContextLiveTest to create nodes using the abstraction, which is much easier |
| @Test(groups = "live", singleThreaded = true) |
| public class LoadBalancerApiLiveTest extends BaseComputeServiceContextLiveTest { |
| |
| private static final String lbName = String.format("lb-%s-%s", LoadBalancerApiLiveTest.class.getSimpleName() |
| .toLowerCase(), System.getProperty("user.name")); |
| |
| private Predicate<URI> resourceDeleted; |
| private PublicIpAvailablePredicateFactory publicIpAvailable; |
| private Predicate<Supplier<Provisionable>> resourceAvailable; |
| private AzureComputeApi api; |
| |
| private String location; |
| private LoadBalancerApi lbApi; |
| private NetworkInterfaceCardApi nicApi; |
| |
| private LoadBalancer lb; |
| private String group; |
| private List<String> nicNames; |
| |
| public LoadBalancerApiLiveTest() { |
| provider = "azurecompute-arm"; |
| group = getClass().getSimpleName().toLowerCase(); |
| } |
| |
| @Override |
| protected Properties setupProperties() { |
| Properties properties = super.setupProperties(); |
| AzureLiveTestUtils.defaultProperties(properties); |
| checkNotNull(setIfTestSystemPropertyPresent(properties, "oauth.endpoint"), "test.oauth.endpoint"); |
| return properties; |
| } |
| |
| @Override |
| protected void initializeContext() { |
| super.initializeContext(); |
| resourceDeleted = context.utils().injector().getInstance(Key.get(new TypeLiteral<Predicate<URI>>() { |
| }, Names.named(TIMEOUT_RESOURCE_DELETED))); |
| publicIpAvailable = context.utils().injector().getInstance(PublicIpAvailablePredicateFactory.class); |
| resourceAvailable = context.utils().injector() |
| .getInstance(Key.get(new TypeLiteral<Predicate<Supplier<Provisionable>>>() { |
| })); |
| api = view.unwrapApi(AzureComputeApi.class); |
| } |
| |
| @Override |
| @BeforeClass |
| public void setupContext() { |
| super.setupContext(); |
| // Use the resource name conventions used in the abstraction so the nodes |
| // can see the load balancer |
| location = view.getComputeService().templateBuilder().build().getLocation().getId(); |
| view.unwrapApi(AzureComputeApi.class).getResourceGroupApi().create(group, location, null); |
| lbApi = api.getLoadBalancerApi(group); |
| nicApi = api.getNetworkInterfaceCardApi(group); |
| } |
| |
| @Override |
| @AfterClass(alwaysRun = true) |
| protected void tearDownContext() { |
| try { |
| view.getComputeService().destroyNodesMatching(inGroup(group)); |
| } finally { |
| try { |
| URI uri = api.getResourceGroupApi().delete(group); |
| assertResourceDeleted(uri); |
| } finally { |
| super.tearDownContext(); |
| } |
| } |
| } |
| |
| @Test |
| public void testDeleteLoadBalancerDoesNotExist() { |
| URI uri = lbApi.delete(lbName); |
| assertNull(uri); |
| } |
| |
| @Test(dependsOnMethods = "testDeleteLoadBalancerDoesNotExist") |
| public void testCreateLoadBalancer() { |
| LoadBalancer createLB = newLoadBalancer(lbName, location); |
| |
| PublicIPAddress publicIP = createPublicIPAddress("Ip4LoadBalancer"); |
| FrontendIPConfigurationsProperties fronendProps = FrontendIPConfigurationsProperties.builder() |
| .publicIPAddress(IdReference.create(publicIP.id())).build(); |
| FrontendIPConfigurations frontendIps = FrontendIPConfigurations.create("ipConfigs", null, fronendProps, null); |
| LoadBalancerProperties props = LoadBalancerProperties.builder() |
| .frontendIPConfigurations(ImmutableList.of(frontendIps)).build(); |
| |
| lb = lbApi.createOrUpdate(lbName, createLB.location(), createLB.tags(), props); |
| assertNotNull(lb); |
| } |
| |
| @Test(dependsOnMethods = "testCreateLoadBalancer") |
| public void testListLoadBalancers() { |
| List<LoadBalancer> result = lbApi.list(); |
| |
| // Verify we have something |
| assertNotNull(result); |
| assertTrue(result.size() > 0); |
| |
| // Check that the load balancer matches the one we originally passed in |
| assertTrue(any(result, new Predicate<LoadBalancer>() { |
| @Override |
| public boolean apply(LoadBalancer input) { |
| return lb.name().equals(input.name()); |
| } |
| })); |
| } |
| |
| @Test(dependsOnMethods = "testCreateLoadBalancer") |
| public void testGetLoadBalancer() { |
| lb = lbApi.get(lbName); |
| assertNotNull(lb); |
| } |
| |
| @Test(dependsOnMethods = "testGetLoadBalancer") |
| public void testAddProbe() { |
| ProbeProperties probeProps = ProbeProperties.builder().protocol(ProbeProperties.Protocol.Http).port(80) |
| .requestPath("/").intervalInSeconds(5).numberOfProbes(2).build(); |
| |
| Probe probe = Probe.create("probetest", null, probeProps, null); |
| LoadBalancerProperties props = lb.properties().toBuilder().probes(ImmutableList.of(probe)).build(); |
| |
| lb = updateLoadBalancer(lbName, props); |
| |
| assertEquals(lb.properties().probes().size(), 1); |
| assertEquals(lb.properties().probes().get(0).name(), probe.name()); |
| } |
| |
| @Test(dependsOnMethods = "testGetLoadBalancer") |
| public void testAddBackendPool() throws Exception { |
| List<IdReference> rules = newArrayList(transform(lb.properties().loadBalancingRules(), ToIdReference)); |
| BackendAddressPool pool = BackendAddressPool.create("backpools", null, BackendAddressPoolProperties.builder() |
| .loadBalancingRules(rules).build(), null); |
| |
| LoadBalancerProperties props = lb.properties().toBuilder().backendAddressPools(ImmutableList.of(pool)).build(); |
| |
| lb = updateLoadBalancer(lbName, props); |
| |
| assertEquals(lb.properties().backendAddressPools().size(), 1); |
| assertEquals(lb.properties().backendAddressPools().get(0).name(), pool.name()); |
| } |
| |
| @Test(dependsOnMethods = { "testAddProbe", "testAddBackendPool" }) |
| public void testAddLoadBalancingRule() { |
| IdReference frontendIp = IdReference.create(lb.properties().frontendIPConfigurations().get(0).id()); |
| IdReference probe = IdReference.create(lb.properties().probes().get(0).id()); |
| IdReference backendPool = IdReference.create(lb.properties().backendAddressPools().get(0).id()); |
| |
| LoadBalancingRuleProperties ruleProperties = LoadBalancingRuleProperties.builder() |
| .frontendIPConfiguration(frontendIp).backendAddressPool(backendPool).frontendPort(80).backendPort(80) |
| .protocol(Protocol.Tcp).probe(probe).build(); |
| |
| LoadBalancingRule rule = LoadBalancingRule.create("lbRule1", null, ruleProperties, null); |
| LoadBalancerProperties props = lb.properties().toBuilder().loadBalancingRules(ImmutableList.of(rule)).build(); |
| |
| lb = updateLoadBalancer(lbName, props); |
| |
| assertEquals(lb.properties().loadBalancingRules().size(), 1); |
| assertEquals(lb.properties().loadBalancingRules().get(0).name(), rule.name()); |
| } |
| |
| @Test(dependsOnMethods = { "testAddBackendPool", "testAddProbe", "testAddLoadBalancingRule" }) |
| public void testAttachNodesToBackendPool() throws Exception { |
| nicNames = createVirtualMachinesInGroupAndGetNicRefs(group, 2); |
| |
| // Add the first IP of each node to the pool |
| List<NetworkInterfaceCard> attachedNics = new ArrayList<NetworkInterfaceCard>(); |
| BackendAddressPool targetPool = lb.properties().backendAddressPools().get(0); |
| for (String nicName : nicNames) { |
| attachedNics.add(attachNicToBackendPool(nicName, targetPool)); |
| } |
| |
| // Refresh the LB after having attached NICs to the pool |
| lb = lbApi.get(lbName); |
| List<BackendAddressPool> pools = lb.properties().backendAddressPools(); |
| assertEquals(pools.size(), 1); |
| |
| List<IdReference> backendIps = pools.get(0).properties().backendIPConfigurations(); |
| assertEquals(backendIps.size(), attachedNics.size()); |
| assertTrue(backendIps.containsAll(newArrayList(transform(attachedNics, ToFirstIpReference)))); |
| } |
| |
| @Test(dependsOnMethods = "testAttachNodesToBackendPool") |
| public void testAddInboundNatRule() { |
| IdReference frontendIp = IdReference.create(lb.properties().frontendIPConfigurations().get(0).id()); |
| |
| InboundNatRuleProperties natProps = InboundNatRuleProperties.builder().frontendIPConfiguration(frontendIp) |
| .frontendPort(5679).backendPort(56710).protocol(Tcp).build(); |
| |
| InboundNatRule natRule = InboundNatRule.create("inboundnat", null, natProps, null); |
| LoadBalancerProperties props = lb.properties().toBuilder().inboundNatRules(ImmutableList.of(natRule)).build(); |
| |
| lb = updateLoadBalancer(lbName, props); |
| |
| assertEquals(lb.properties().inboundNatRules().size(), 1); |
| assertEquals(lb.properties().inboundNatRules().get(0).name(), natRule.name()); |
| |
| InboundNatRule createdRule = lb.properties().inboundNatRules().get(0); |
| NetworkInterfaceCard updatedNic = attachNicToNatRule(nicNames.get(0), createdRule); |
| List<IdReference> natRulesInNic = updatedNic.properties().ipConfigurations().get(0).properties() |
| .loadBalancerInboundNatRules(); |
| |
| assertEquals(natRulesInNic.size(), 1); |
| assertEquals(natRulesInNic.get(0), IdReference.create(createdRule.id())); |
| |
| // Refresh the LB after having attached NICs to the pool |
| lb = lbApi.get(lbName); |
| |
| IdReference backendIpRef = IdReference.create(updatedNic.properties().ipConfigurations().get(0).id()); |
| assertEquals(lb.properties().inboundNatRules().size(), 1); |
| assertEquals(lb.properties().inboundNatRules().get(0).properties().backendIPConfiguration(), backendIpRef); |
| |
| } |
| |
| @Test(dependsOnMethods = { "testCreateLoadBalancer", "testListLoadBalancers", "testGetLoadBalancer", "testAddProbe", |
| "testAddLoadBalancingRule", "testAddBackendPool", "testAttachNodesToBackendPool", "testAddInboundNatRule" }, alwaysRun = true) |
| public void deleteLoadBalancer() { |
| URI uri = lbApi.delete(lbName); |
| assertResourceDeleted(uri); |
| } |
| |
| private PublicIPAddress createPublicIPAddress(final String publicIpAddressName) { |
| final PublicIPAddressApi ipApi = view.unwrapApi(AzureComputeApi.class).getPublicIPAddressApi(group); |
| PublicIPAddress publicIPAddress = ipApi.get(publicIpAddressName); |
| |
| if (publicIPAddress == null) { |
| final Map<String, String> tags = ImmutableMap.of("testkey", "testvalue"); |
| PublicIPAddressProperties properties = PublicIPAddressProperties.builder().publicIPAllocationMethod("Static") |
| .idleTimeoutInMinutes(4).build(); |
| publicIPAddress = ipApi.createOrUpdate(publicIpAddressName, location, tags, properties); |
| |
| checkState(publicIpAvailable.create(group).apply(publicIpAddressName), |
| "Public IP was not provisioned in the configured timeout"); |
| } |
| |
| return publicIPAddress; |
| } |
| |
| private LoadBalancer newLoadBalancer(final String lbName, final String locationName) { |
| FrontendIPConfigurationsProperties frontendIPConfigurationsProperties = FrontendIPConfigurationsProperties |
| .builder().build(); |
| FrontendIPConfigurations frontendIPConfigurations = FrontendIPConfigurations.create("ipConfigs", null, |
| frontendIPConfigurationsProperties, null); |
| return LoadBalancer |
| .builder() |
| .name(lbName) |
| .location(locationName) |
| .properties( |
| LoadBalancerProperties.builder().frontendIPConfigurations(ImmutableList.of(frontendIPConfigurations)) |
| .build()).build(); |
| } |
| |
| private void assertResourceDeleted(final URI uri) { |
| if (uri != null) { |
| assertTrue(resourceDeleted.apply(uri), |
| String.format("Resource %s was not terminated in the configured timeout", uri)); |
| } |
| } |
| |
| private List<String> createVirtualMachinesInGroupAndGetNicRefs(final String group, final int count) |
| throws RunNodesException { |
| |
| // To add multiple nodes in a LB they must belong to the same availability |
| // set |
| AvailabilitySetProperties props = AvailabilitySetProperties.builder().platformUpdateDomainCount(count) |
| .platformFaultDomainCount(count).build(); |
| AvailabilitySet as = AvailabilitySet.managed().name(group).properties(props).build(); |
| |
| Set<? extends NodeMetadata> nodes = view.getComputeService().createNodesInGroup(group, count, |
| availabilitySet(as).resourceGroup(this.group)); |
| |
| List<String> nicNames = new ArrayList<String>(); |
| for (NodeMetadata node : nodes) { |
| ResourceGroupAndName resourceGroupAndName = ResourceGroupAndName.fromSlashEncoded(node.getId()); |
| VirtualMachine vm = api.getVirtualMachineApi(resourceGroupAndName.resourceGroup()).get( |
| resourceGroupAndName.name()); |
| |
| String nicName = extractName(vm.properties().networkProfile().networkInterfaces().get(0).id()); |
| nicNames.add(nicName); |
| } |
| |
| return nicNames; |
| } |
| |
| private NetworkInterfaceCard attachNicToBackendPool(final String nicName, BackendAddressPool pool) { |
| List<IdReference> poolRefs = ImmutableList.of(IdReference.create(pool.id())); |
| |
| // Assume we are attaching the first IP to the Load Balancer |
| NetworkInterfaceCard nic = nicApi.get(nicName); |
| |
| IpConfigurationProperties ipProps = nic.properties().ipConfigurations().get(0).properties().toBuilder() |
| .loadBalancerBackendAddressPools(poolRefs).build(); |
| List<IpConfiguration> ips = ImmutableList.of(nic.properties().ipConfigurations().get(0).toBuilder() |
| .properties(ipProps).build()); |
| |
| NetworkInterfaceCardProperties nicProps = nic.properties().toBuilder().ipConfigurations(ips).build(); |
| |
| nicApi.createOrUpdate(nicName, location, nicProps, null); |
| |
| resourceAvailable.apply(new Supplier<Provisionable>() { |
| @Override |
| public Provisionable get() { |
| NetworkInterfaceCard updated = nicApi.get(nicName); |
| return updated == null ? null : updated.properties(); |
| } |
| }); |
| |
| return nicApi.get(nicName); |
| } |
| |
| private NetworkInterfaceCard attachNicToNatRule(final String nicName, InboundNatRule rule) { |
| List<IdReference> natRuleRefs = ImmutableList.of(IdReference.create(rule.id())); |
| |
| // Assume we are attaching the first IP to the NAT rule |
| NetworkInterfaceCard nic = nicApi.get(nicName); |
| |
| IpConfigurationProperties ipProps = nic.properties().ipConfigurations().get(0).properties().toBuilder() |
| .loadBalancerInboundNatRules(natRuleRefs).build(); |
| List<IpConfiguration> ips = ImmutableList.of(nic.properties().ipConfigurations().get(0).toBuilder() |
| .properties(ipProps).build()); |
| |
| NetworkInterfaceCardProperties nicProps = nic.properties().toBuilder().ipConfigurations(ips).build(); |
| |
| nicApi.createOrUpdate(nicName, location, nicProps, null); |
| |
| resourceAvailable.apply(new Supplier<Provisionable>() { |
| @Override |
| public Provisionable get() { |
| NetworkInterfaceCard updated = nicApi.get(nicName); |
| return updated == null ? null : updated.properties(); |
| } |
| }); |
| |
| return nicApi.get(nicName); |
| } |
| |
| private LoadBalancer updateLoadBalancer(final String name, LoadBalancerProperties props) { |
| lbApi.createOrUpdate(name, location, null, props); |
| resourceAvailable.apply(new Supplier<Provisionable>() { |
| @Override |
| public Provisionable get() { |
| LoadBalancer updated = lbApi.get(name); |
| return updated == null ? null : updated.properties(); |
| } |
| }); |
| return lbApi.get(name); |
| } |
| |
| private static final Function<LoadBalancingRule, IdReference> ToIdReference = new Function<LoadBalancingRule, IdReference>() { |
| @Override |
| public IdReference apply(LoadBalancingRule input) { |
| return IdReference.create(input.id()); |
| } |
| }; |
| |
| private static final Function<NetworkInterfaceCard, IdReference> ToFirstIpReference = new Function<NetworkInterfaceCard, IdReference>() { |
| @Override |
| public IdReference apply(NetworkInterfaceCard input) { |
| return IdReference.create(input.properties().ipConfigurations().get(0).id()); |
| } |
| }; |
| |
| } |