/* * 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.apache.brooklyn.location.jclouds; import static org.testng.Assert.assertEquals; import static org.testng.Assert.fail; import java.util.Map; import java.util.NoSuchElementException; import java.util.Set; import org.apache.brooklyn.core.config.MapConfigKey; import org.apache.brooklyn.core.config.SetConfigKey; import org.apache.brooklyn.core.internal.BrooklynProperties; import org.apache.brooklyn.core.location.cloud.CloudLocationConfig; import org.apache.brooklyn.core.location.internal.LocationInternal; import org.apache.brooklyn.core.mgmt.internal.LocalManagementContext; import org.apache.brooklyn.core.test.entity.LocalManagementContextForTests; import org.apache.brooklyn.util.collections.MutableMap; import org.apache.brooklyn.util.collections.MutableSet; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.testng.Assert; import org.testng.annotations.AfterMethod; import org.testng.annotations.BeforeMethod; import org.testng.annotations.Test; public class JcloudsLocationResolverTest { private static final Logger log = LoggerFactory.getLogger(JcloudsLocationResolverTest.class); private LocalManagementContext managementContext; private BrooklynProperties brooklynProperties; @BeforeMethod(alwaysRun = true) public void setUp() throws Exception { managementContext = LocalManagementContextForTests.newInstance(); brooklynProperties = managementContext.getBrooklynProperties(); brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.identity", "aws-ec2-id"); brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.credential", "aws-ec2-cred"); brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.identity", "cloudservers-uk-id"); brooklynProperties.put("brooklyn.location.jclouds.rackspace-cloudservers-uk.credential", "cloudservers-uk-cred"); } @AfterMethod(alwaysRun = true) public void tearDown() throws Exception { if (managementContext != null) managementContext.terminate(); } @Test public void testJcloudsTakesDotSeparateProperty() { brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.loginUser.privateKeyFile", "myfile"); String file = resolve("jclouds:aws-ec2").getConfig(JcloudsLocation.LOGIN_USER_PRIVATE_KEY_FILE); assertEquals(file, "myfile"); } @Test public void testJcloudsTakesProviderScopedProperties() { brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.privateKeyFile", "myprivatekeyfile"); brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.publicKeyFile", "mypublickeyfile"); brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.privateKeyData", "myprivateKeyData"); brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.publicKeyData", "myPublicKeyData"); brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.privateKeyPassphrase", "myprivateKeyPassphrase"); Map<String, Object> conf = resolve("jclouds:aws-ec2").config().getBag().getAllConfig(); assertEquals(conf.get("privateKeyFile"), "myprivatekeyfile"); assertEquals(conf.get("publicKeyFile"), "mypublickeyfile"); assertEquals(conf.get("privateKeyData"), "myprivateKeyData"); assertEquals(conf.get("publicKeyData"), "myPublicKeyData"); assertEquals(conf.get("privateKeyPassphrase"), "myprivateKeyPassphrase"); } @Test public void testJcloudsTakesGenericScopedProperties() { brooklynProperties.put("brooklyn.location.jclouds.privateKeyFile", "myprivatekeyfile"); brooklynProperties.put("brooklyn.location.jclouds.publicKeyFile", "mypublickeyfile"); brooklynProperties.put("brooklyn.location.jclouds.privateKeyData", "myprivateKeyData"); brooklynProperties.put("brooklyn.location.jclouds.publicKeyData", "myPublicKeyData"); brooklynProperties.put("brooklyn.location.jclouds.privateKeyPassphrase", "myprivateKeyPassphrase"); Map<String, Object> conf = resolve("jclouds:aws-ec2").config().getBag().getAllConfig(); assertEquals(conf.get("privateKeyFile"), "myprivatekeyfile"); assertEquals(conf.get("publicKeyFile"), "mypublickeyfile"); assertEquals(conf.get("privateKeyData"), "myprivateKeyData"); assertEquals(conf.get("publicKeyData"), "myPublicKeyData"); assertEquals(conf.get("privateKeyPassphrase"), "myprivateKeyPassphrase"); } @Test public void testJcloudsTakesDeprecatedProperties() { brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.private-key-file", "myprivatekeyfile"); brooklynProperties.put("brooklyn.location.jclouds.public-key-file", "mypublickeyfile"); brooklynProperties.put("brooklyn.location.jclouds.private-key-data", "myprivateKeyData"); brooklynProperties.put("brooklyn.location.jclouds.public-key-data", "myPublicKeyData"); brooklynProperties.put("brooklyn.location.jclouds.private-key-passphrase", "myprivateKeyPassphrase"); brooklynProperties.put("brooklyn.location.jclouds.image-id", "myimageid"); Map<String, Object> conf = resolve("jclouds:aws-ec2").config().getBag().getAllConfig(); assertEquals(conf.get("privateKeyFile"), "myprivatekeyfile"); assertEquals(conf.get("publicKeyFile"), "mypublickeyfile"); assertEquals(conf.get("privateKeyData"), "myprivateKeyData"); assertEquals(conf.get("publicKeyData"), "myPublicKeyData"); assertEquals(conf.get("privateKeyPassphrase"), "myprivateKeyPassphrase"); assertEquals(conf.get("imageId"), "myimageid"); } @Test public void testJcloudsPropertiesPrecedence() { brooklynProperties.put("brooklyn.location.named.myaws-ec2", "jclouds:aws-ec2"); // prefer those in "named" over everything else brooklynProperties.put("brooklyn.location.named.myaws-ec2.privateKeyFile", "privateKeyFile-inNamed"); brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.privateKeyFile", "privateKeyFile-inProviderSpecific"); brooklynProperties.put("brooklyn.location.jclouds.privateKeyFile", "privateKeyFile-inJcloudsGeneric"); // prefer those in provider-specific over generic brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.publicKeyFile", "publicKeyFile-inProviderSpecific"); brooklynProperties.put("brooklyn.location.jclouds.publicKeyFile", "publicKeyFile-inJcloudsGeneric"); // prefer deprecated properties in "named" over those less specific brooklynProperties.put("brooklyn.location.named.myaws-ec2.private-key-data", "privateKeyData-inNamed"); brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.privateKeyData", "privateKeyData-inProviderSpecific"); brooklynProperties.put("brooklyn.location.jclouds.privateKeyData", "privateKeyData-inJcloudsGeneric"); // prefer generic if nothing else brooklynProperties.put("brooklyn.location.jclouds.publicKeyData", "publicKeyData-inJcloudsGeneric"); // prefer "named" over everything else: confirm deprecated don't get // transformed to overwrite it accidentally brooklynProperties .put("brooklyn.location.named.myaws-ec2.privateKeyPassphrase", "privateKeyPassphrase-inNamed"); brooklynProperties.put("brooklyn.location.jclouds.aws-ec2.private-key-passphrase", "privateKeyPassphrase-inProviderSpecific"); brooklynProperties.put("brooklyn.location.jclouds.private-key-passphrase", "privateKeyPassphrase-inJcloudsGeneric"); Map<String, Object> conf = resolve("named:myaws-ec2").config().getBag().getAllConfig(); assertEquals(conf.get("privateKeyFile"), "privateKeyFile-inNamed"); assertEquals(conf.get("publicKeyFile"), "publicKeyFile-inProviderSpecific"); assertEquals(conf.get("privateKeyData"), "privateKeyData-inNamed"); assertEquals(conf.get("publicKeyData"), "publicKeyData-inJcloudsGeneric"); assertEquals(conf.get("privateKeyPassphrase"), "privateKeyPassphrase-inNamed"); } @Test public void testJcloudsLoads() { Assert.assertTrue(resolve("jclouds:aws-ec2") instanceof JcloudsLocation); } @Test public void testJcloudsImplicitLoads() { Assert.assertTrue(resolve("aws-ec2") instanceof JcloudsLocation); } @Test public void testJcloudsLocationLoads() { Assert.assertTrue(resolve("aws-ec2:eu-west-1") instanceof JcloudsLocation); } @Test public void testJcloudsRegionOnlyLoads() { Assert.assertTrue(resolve("eu-west-1") instanceof JcloudsLocation); } @Test public void testJcloudsEndpointLoads() { JcloudsLocation loc = resolve("jclouds:openstack-nova:http://foo/api"); assertEquals(loc.getProvider(), "openstack-nova"); assertEquals(loc.getEndpoint(), "http://foo/api"); } @Test public void testJcloudsEndpointLoadsAsProperty() { brooklynProperties.put("brooklyn.location.jclouds.openstack-nova.endpoint", "myendpoint"); JcloudsLocation loc = resolve("jclouds:openstack-nova"); // just checking Assert.assertEquals(loc.config().getLocalBag().getStringKey("endpoint"), "myendpoint"); Assert.assertEquals(loc.getConfig(CloudLocationConfig.CLOUD_ENDPOINT), "myendpoint"); // this is the one we really care about!: assertEquals(loc.getEndpoint(), "myendpoint"); } @Test public void testJcloudsLegacyRandomProperty() { brooklynProperties.put("brooklyn.location.jclouds.openstack-nova.foo", "bar"); JcloudsLocation loc = resolve("jclouds:openstack-nova"); Assert.assertEquals(loc.config().getLocalBag().getStringKey("foo"), "bar"); } @Test public void testJcloudsRandomProperty() { brooklynProperties.put("brooklyn.location.jclouds.openstack-nova.foo", "bar"); JcloudsLocation loc = resolve("jclouds:openstack-nova"); Assert.assertEquals(loc.config().getLocalBag().getStringKey("foo"), "bar"); } @Test public void testThrowsOnInvalid() throws Exception { // Tries to treat "wrongprefix" as a cloud provider assertThrows("wrongprefix:aws-ec2:us-east-1", NoSuchElementException.class); // no provider assertThrows("jclouds", IllegalArgumentException.class); // empty provider assertThrows("jclouds:", IllegalArgumentException.class); // invalid provider assertThrows("jclouds:doesnotexist", NoSuchElementException.class); } @Test public void testResolvesJclouds() throws Exception { // test with provider + region assertJcloudsEquals(resolve("jclouds:aws-ec2:us-east-1"), "aws-ec2", "us-east-1"); // test with provider that has no region assertJcloudsEquals(resolve("jclouds:rackspace-cloudservers-uk"), "rackspace-cloudservers-uk", null); } @Test public void testJcloudsRegionOverridesParent() { Map<String, Object> conf; brooklynProperties.put("brooklyn.location.named.softlayer-was", "jclouds:softlayer:was01"); brooklynProperties.put("brooklyn.location.named.softlayer-was2", "jclouds:softlayer:was01"); brooklynProperties.put("brooklyn.location.named.softlayer-was2.region", "was02"); conf = resolve("named:softlayer-was").config().getBag().getAllConfig(); assertEquals(conf.get("region"), "was01"); conf = resolve("named:softlayer-was2").config().getBag().getAllConfig(); assertEquals(conf.get("region"), "was02"); conf = ((LocationInternal) managementContext.getLocationRegistry().resolve("named:softlayer-was2", MutableMap.of("region", "was03"))) .config().getBag().getAllConfig();; assertEquals(conf.get("region"), "was03"); } // TODO Visual inspection test that it logs warnings @Test public void testLogsWarnings() throws Exception { assertJcloudsEquals(resolve("jclouds:jclouds:aws-ec2:us-east-1"), "aws-ec2", "us-east-1"); assertJcloudsEquals(resolve("us-east-1"), "aws-ec2", "us-east-1"); // TODO Should we enforce a jclouds prefix? Currently we don't // assertJcloudsEquals(resolve("aws-ec2:us-east-1"), "aws-ec2", // "us-east-1"); } @Test public void testResolvesJcloudsFromNamedOfNamedWithPropertiesOverriddenCorrectly() throws Exception { brooklynProperties.put("brooklyn.location.jclouds.softlayer.prop1", "1"); brooklynProperties.put("brooklyn.location.jclouds.softlayer.prop2", "1"); brooklynProperties.put("brooklyn.location.jclouds.softlayer.prop3", "1"); brooklynProperties.put("brooklyn.location.named.foo", "jclouds:softlayer:138124"); brooklynProperties.put("brooklyn.location.named.foo.prop2", "2"); brooklynProperties.put("brooklyn.location.named.foo.prop3", "2"); brooklynProperties.put("brooklyn.location.named.bar", "named:foo"); brooklynProperties.put("brooklyn.location.named.bar.prop3", "3"); JcloudsLocation l = resolve("named:bar"); assertJcloudsEquals(l, "softlayer", "138124"); Assert.assertEquals(l.config().getLocalBag().getStringKey("prop3"), "3"); Assert.assertEquals(l.config().getLocalBag().getStringKey("prop2"), "2"); Assert.assertEquals(l.config().getLocalBag().getStringKey("prop1"), "1"); } @Test public void testResolvesListAndMapProperties() throws Exception { brooklynProperties.put("brooklyn.location.jclouds.softlayer.prop1", "[ a, b ]"); brooklynProperties.put("brooklyn.location.jclouds.softlayer.prop2", "{ a: 1, b: 2 }"); brooklynProperties.put("brooklyn.location.named.foo", "jclouds:softlayer:ams01"); JcloudsLocation l = resolve("named:foo"); assertJcloudsEquals(l, "softlayer", "ams01"); assertEquals(l.config().get(new SetConfigKey<String>(String.class, "prop1")), MutableSet.of("a", "b")); assertEquals(l.config().get(new MapConfigKey<String>(String.class, "prop2")), MutableMap.of("a", 1, "b", 2)); } @Test public void testResolvesListAndMapPropertiesWithoutMergeOnInheritance() throws Exception { // when we have a yaml way to specify config we may wish to have different semantics; // it could depend on the collection config key whether to merge on inheritance brooklynProperties.put("brooklyn.location.jclouds.softlayer.prop1", "[ a, b ]"); brooklynProperties.put("brooklyn.location.jclouds.softlayer.prop2", "{ a: 1, b: 2 }"); brooklynProperties.put("brooklyn.location.named.foo", "jclouds:softlayer:ams01"); brooklynProperties.put("brooklyn.location.named.foo.prop1", "[ a: 1, c: 3 ]"); brooklynProperties.put("brooklyn.location.named.foo.prop2", "{ b: 3, c: 3 }"); brooklynProperties.put("brooklyn.location.named.bar", "named:foo"); brooklynProperties.put("brooklyn.location.named.bar.prop2", "{ c: 4, d: 4 }"); // these do NOT affect the maps brooklynProperties.put("brooklyn.location.named.foo.prop2.z", "9"); brooklynProperties.put("brooklyn.location.named.foo.prop3.z", "9"); JcloudsLocation l = resolve("named:bar"); assertJcloudsEquals(l, "softlayer", "ams01"); Set<? extends String> prop1 = l.config().get(new SetConfigKey<String>(String.class, "prop1")); log.info("prop1: "+prop1); assertEquals(prop1, MutableSet.of("a: 1", "c: 3")); Map<String, String> prop2 = l.config().get(new MapConfigKey<String>(String.class, "prop2")); log.info("prop2: "+prop2); assertEquals(prop2, MutableMap.of("c", 4, "d", 4)); Map<String, String> prop3 = l.config().get(new MapConfigKey<String>(String.class, "prop3")); log.info("prop3: "+prop3); assertEquals(prop3, null); } private void assertJcloudsEquals(JcloudsLocation loc, String expectedProvider, String expectedRegion) { assertEquals(loc.getProvider(), expectedProvider); assertEquals(loc.getRegion(), expectedRegion); } private void assertThrows(String val, Class<?> expectedExceptionType) throws Exception { try { resolve(val); fail(); } catch (Exception e) { if (!expectedExceptionType.isInstance(e)) throw e; // otherwise success } } @Test(expectedExceptions = { NoSuchElementException.class, IllegalArgumentException.class }, expectedExceptionsMessageRegExp = ".*insufficient.*") public void testJcloudsOnlyFails() { resolve("jclouds"); } private JcloudsLocation resolve(String spec) { return (JcloudsLocation) managementContext.getLocationRegistry().resolve(spec); } }