org.apache.whirr.ClusterSpecTest.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.whirr.ClusterSpecTest.java

Source

/**
 * 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.whirr;

import static com.google.common.collect.Iterables.get;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertThat;

import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.Set;

import org.apache.commons.configuration.CompositeConfiguration;
import org.apache.commons.configuration.Configuration;
import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;
import org.apache.commons.io.IOUtils;
import org.apache.whirr.util.KeyPair;
import org.junit.Assert;
import org.junit.Test;

import com.google.common.collect.Iterables;
import com.google.common.collect.Iterators;
import com.google.common.collect.Lists;
import com.google.common.collect.Sets;
import com.google.common.io.Files;
import com.jcraft.jsch.JSchException;

public class ClusterSpecTest {

    @Test
    public void testDefaultsAreSet() throws ConfigurationException, JSchException, IOException {
        ClusterSpec spec = ClusterSpec.withTemporaryKeys();
        assertThat(spec.getClusterUser(), is(System.getProperty("user.name")));
        assertThat(spec.getMaxStartupRetries(), is(1));
    }

    @Test
    public void testDefaultsCanBeOverridden() throws ConfigurationException, JSchException, IOException {
        Configuration conf = new PropertiesConfiguration();
        conf.setProperty(ClusterSpec.Property.RUN_URL_BASE.getConfigName(), "http://example.org");
        ClusterSpec spec = ClusterSpec.withNoDefaults(conf);
        assertThat(spec.getRunUrlBase(), is("http://example.org"));
    }

    @Test
    public void testGetConfigurationForKeysWithPrefix() throws ConfigurationException, JSchException, IOException {
        Configuration conf = new PropertiesConfiguration();
        conf.setProperty("a.b", 1);
        conf.setProperty("b.a", 2);
        conf.setProperty("a.c", 3);

        ClusterSpec spec = ClusterSpec.withNoDefaults(conf);
        Configuration prefixConf = spec.getConfigurationForKeysWithPrefix("a");

        List<String> prefixKeys = Lists.newArrayList();
        Iterators.addAll(prefixKeys, prefixConf.getKeys());

        assertThat(prefixKeys.size(), is(2));
        assertThat(prefixKeys.get(0), is("a.b"));
        assertThat(prefixKeys.get(1), is("a.c"));
    }

    @Test
    public void testEnvVariableInterpolation() {
        Map<String, String> envMap = System.getenv();
        assertThat(envMap.isEmpty(), is(false));

        String undefinedEnvVar = "UNDEFINED_ENV_VAR";
        assertThat(envMap.containsKey(undefinedEnvVar), is(false));

        Entry<String, String> firstEntry = Iterables.get(envMap.entrySet(), 0);
        Configuration conf = new PropertiesConfiguration();
        conf.setProperty("a", String.format("${env:%s}", firstEntry.getKey()));
        conf.setProperty("b", String.format("${env:%s}", undefinedEnvVar));

        assertThat(conf.getString("a"), is(firstEntry.getValue()));
        assertThat(conf.getString("b"), is(String.format("${env:%s}", undefinedEnvVar)));
    }

    @Test
    public void testDefaultPublicKey() throws ConfigurationException, JSchException, IOException {
        Map<String, File> keys = KeyPair.generateTemporaryFiles();

        Configuration conf = new PropertiesConfiguration();
        conf.setProperty("whirr.private-key-file", keys.get("private").getAbsolutePath());
        // If no public-key-file is specified it should append .pub to the private-key-file

        ClusterSpec spec = ClusterSpec.withNoDefaults(conf);
        Assert.assertEquals(IOUtils.toString(new FileReader(keys.get("public"))), spec.getPublicKey());
    }

    @Test(expected = ConfigurationException.class)
    public void testDummyPrivateKey() throws JSchException, IOException, ConfigurationException {
        File privateKeyFile = File.createTempFile("private", "key");
        privateKeyFile.deleteOnExit();
        Files.write(
                ("-----BEGIN RSA PRIVATE KEY-----\n" + "DUMMY FILE\n" + "-----END RSA PRIVATE KEY-----").getBytes(),
                privateKeyFile);

        Configuration conf = new PropertiesConfiguration();
        conf.setProperty("whirr.private-key-file", privateKeyFile.getAbsolutePath());

        ClusterSpec.withNoDefaults(conf);
    }

    @Test(expected = ConfigurationException.class)
    public void testEncryptedPrivateKey() throws JSchException, IOException, ConfigurationException {
        File privateKey = KeyPair.generateTemporaryFiles("dummy").get("private");

        Configuration conf = new PropertiesConfiguration();
        conf.setProperty("whirr.private-key-file", privateKey.getAbsolutePath());

        ClusterSpec.withNoDefaults(conf);
    }

    @Test(expected = ConfigurationException.class)
    public void testMissingPrivateKey() throws ConfigurationException {
        Configuration conf = new PropertiesConfiguration();
        conf.setProperty("whirr.private-key-file", "/dummy/path/that/does/not/exists");

        ClusterSpec.withNoDefaults(conf);
    }

    @Test(expected = ConfigurationException.class)
    public void testMissingPublicKey() throws JSchException, IOException, ConfigurationException {
        File privateKey = KeyPair.generateTemporaryFiles().get("private");

        Configuration conf = new PropertiesConfiguration();
        conf.setProperty("whirr.private-key-file", privateKey.getAbsolutePath());
        conf.setProperty("whirr.public-key-file", "/dummy/path/that/does/not/exists");

        ClusterSpec.withNoDefaults(conf);
    }

    @Test(expected = ConfigurationException.class)
    public void testBrokenPublicKey() throws IOException, JSchException, ConfigurationException {
        File privateKey = KeyPair.generateTemporaryFiles().get("private");

        File publicKey = File.createTempFile("public", "key");
        publicKey.deleteOnExit();
        Files.write("ssh-rsa BROKEN PUBLIC KEY".getBytes(), publicKey);

        Configuration conf = new PropertiesConfiguration();
        conf.setProperty("whirr.private-key-file", privateKey.getAbsolutePath());
        conf.setProperty("whirr.public-key-file", publicKey.getAbsolutePath());

        ClusterSpec.withNoDefaults(conf);
    }

    @Test(expected = ConfigurationException.class)
    public void testNotSameKeyPair() throws JSchException, IOException, ConfigurationException {
        Map<String, File> first = KeyPair.generateTemporaryFiles();
        Map<String, File> second = KeyPair.generateTemporaryFiles();

        Configuration conf = new PropertiesConfiguration();
        conf.setProperty("whirr.private-key-file", first.get("private").getAbsolutePath());
        conf.setProperty("whirr.public-key-file", second.get("public").getAbsolutePath());

        ClusterSpec.withNoDefaults(conf);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testMissingCommaInInstanceTemplates() throws Exception {
        Configuration conf = new PropertiesConfiguration();
        conf.setProperty(ClusterSpec.Property.INSTANCE_TEMPLATES.getConfigName(), "1 a+b 2 c+d"); // missing comma
        ClusterSpec.withTemporaryKeys(conf);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testRoleMayNotContainSpaces() {
        InstanceTemplate.builder().numberOfInstance(1).minNumberOfInstances(1).roles("a b").build();
    }

    @Test(expected = IllegalArgumentException.class)
    public void testIllegalArgumentExceptionOnInstancesTemplates() throws Exception {
        Configuration conf = new PropertiesConfiguration();
        conf.addProperty("whirr.instance-templates",
                "1 hadoop-namenode+hadoop-jobtracker,3 hadoop-datanode+hadoop-tasktracker");
        conf.addProperty("whirr.instance-templates-max-percent-failures",
                "60 % hadoop-datanode+hadoop-tasktracker");
        ClusterSpec expectedClusterSpec = ClusterSpec.withNoDefaults(conf);
        List<InstanceTemplate> templates = expectedClusterSpec.getInstanceTemplates();
        InstanceTemplate t1 = templates.get(0);
        assertThat(t1.getMinNumberOfInstances(), is(1));
        InstanceTemplate t2 = templates.get(1);
        assertThat(t2.getMinNumberOfInstances(), is(2));
    }

    @Test(expected = NumberFormatException.class)
    public void testNumberFormatExceptionOnInstancesTemplates() throws Exception {
        Configuration conf = new PropertiesConfiguration();
        conf.addProperty("whirr.instance-templates",
                "1 hadoop-namenode+hadoop-jobtracker,3 hadoop-datanode+hadoop-tasktracker");
        conf.addProperty("whirr.instance-templates-max-percent-failures", "60% hadoop-datanode+hadoop-tasktracker");
        ClusterSpec expectedClusterSpec = ClusterSpec.withNoDefaults(conf);
        List<InstanceTemplate> templates = expectedClusterSpec.getInstanceTemplates();
        InstanceTemplate t1 = templates.get(0);
        assertThat(t1.getMinNumberOfInstances(), is(1));
        InstanceTemplate t2 = templates.get(1);
        assertThat(t2.getMinNumberOfInstances(), is(2));
    }

    @Test
    public void testNumberOfInstancesPerTemplate() throws Exception {
        Configuration conf = new PropertiesConfiguration();
        conf.addProperty("whirr.instance-templates",
                "1 hadoop-namenode+hadoop-jobtracker,3 hadoop-datanode+hadoop-tasktracker");
        conf.addProperty("whirr.instance-templates-max-percent-failures",
                "100 hadoop-namenode+hadoop-jobtracker,60 hadoop-datanode+hadoop-tasktracker");
        ClusterSpec expectedClusterSpec = ClusterSpec.withNoDefaults(conf);
        List<InstanceTemplate> templates = expectedClusterSpec.getInstanceTemplates();
        InstanceTemplate t1 = templates.get(0);
        assertThat(t1.getMinNumberOfInstances(), is(1));
        InstanceTemplate t2 = templates.get(1);
        assertThat(t2.getMinNumberOfInstances(), is(2));

        conf.setProperty("whirr.instance-templates-max-percent-failures", "60 hadoop-datanode+hadoop-tasktracker");
        expectedClusterSpec = ClusterSpec.withNoDefaults(conf);
        templates = expectedClusterSpec.getInstanceTemplates();
        t1 = templates.get(0);
        assertThat(t1.getMinNumberOfInstances(), is(1));
        t2 = templates.get(1);
        assertThat(t2.getMinNumberOfInstances(), is(2));

        conf.addProperty("whirr.instance-templates-minumum-number-of-instances",
                "1 hadoop-datanode+hadoop-tasktracker");
        expectedClusterSpec = ClusterSpec.withNoDefaults(conf);
        templates = expectedClusterSpec.getInstanceTemplates();
        t1 = templates.get(0);
        assertThat(t1.getMinNumberOfInstances(), is(1));
        t2 = templates.get(1);
        assertThat(t2.getMinNumberOfInstances(), is(2));

        conf.setProperty("whirr.instance-templates-minimum-number-of-instances",
                "3 hadoop-datanode+hadoop-tasktracker");
        expectedClusterSpec = ClusterSpec.withNoDefaults(conf);
        templates = expectedClusterSpec.getInstanceTemplates();
        t1 = templates.get(0);
        assertThat(t1.getMinNumberOfInstances(), is(1));
        t2 = templates.get(1);
        assertThat(t2.getMinNumberOfInstances(), is(3));
    }

    @Test
    public void testClusterUserShouldBeCurrentUser() throws Exception {
        ClusterSpec spec = ClusterSpec.withTemporaryKeys();
        assertThat(spec.getClusterUser(), is(System.getProperty("user.name")));
    }

    @Test
    public void testDefaultBlobStoreforComputeProvider() throws Exception {
        for (String pair : new String[] { "ec2:aws-s3", "aws-ec2:aws-s3", "cloudservers:cloudfiles-us",
                "cloudservers-us:cloudfiles-us", "cloudservers-uk:cloudfiles-uk" }) {
            String[] parts = pair.split(":");

            Configuration config = new PropertiesConfiguration();
            config.addProperty("whirr.provider", parts[0]);

            ClusterSpec spec = ClusterSpec.withTemporaryKeys(config);
            assertThat(spec.getBlobStoreProvider(), is(parts[1]));
        }
    }

    @Test
    public void testApplySubroleAliases() throws ConfigurationException {
        CompositeConfiguration c = new CompositeConfiguration();
        Configuration config = new PropertiesConfiguration();
        config.addProperty("whirr.instance-templates",
                "1 puppet:somepup::pet+something-else, 1 something-else-only");
        c.addConfiguration(config);
        InstanceTemplate template = InstanceTemplate.parse(c).get(0);
        Set<String> expected = Sets
                .newLinkedHashSet(Arrays.asList(new String[] { "puppet:somepup::pet", "something-else" }));
        assertThat(template.getRoles(), is(expected));

        InstanceTemplate template2 = InstanceTemplate.parse(c).get(1);
        Set<String> expected2 = Sets.newLinkedHashSet(Arrays.asList(new String[] { "something-else-only" }));
        assertThat(template2.getRoles(), is(expected2));
    }

    @Test
    public void testCopySpec() throws Exception {
        ClusterSpec spec = ClusterSpec.withTemporaryKeys(new PropertiesConfiguration("whirr-core-test.properties"));
        spec.setLocationId("random-location");

        /* check the copy is the same as the original */
        assertThat(spec.copy(), is(spec));
        assertThat(spec.copy().hashCode(), is(spec.hashCode()));
    }

    @Test
    public void testFirewallRules() throws Exception {
        PropertiesConfiguration conf = new PropertiesConfiguration("whirr-core-test.properties");
        conf.setProperty("whirr.firewall-rules", "8000,8001");
        conf.setProperty("whirr.firewall-rules.serviceA", "9000,9001");
        ClusterSpec spec = ClusterSpec.withTemporaryKeys(conf);

        Map<String, List<String>> firewallRules = spec.getFirewallRules();
        assertThat(firewallRules.get(null).equals(Lists.<String>newArrayList("8000", "8001")), is(true));
        assertThat(firewallRules.get("serviceA").equals(Lists.<String>newArrayList("9000", "9001")), is(true));
    }

    @Test
    public void testHardwareIdPerInstanceTemplate() throws Exception {
        PropertiesConfiguration conf = new PropertiesConfiguration("whirr-core-test.properties");
        conf.setProperty("whirr.instance-templates", "2 noop, 1 role1+role2, 1 role1, 3 spots");
        conf.setProperty("whirr.hardware-id", "c1.xlarge");

        conf.setProperty("whirr.templates.noop.hardware-id", "m1.large");
        conf.setProperty("whirr.templates.role1+role2.hardware-id", "t1.micro");
        conf.setProperty("whirr.templates.role1+role2.image-id", "us-east-1/ami-123324");
        conf.setProperty("whirr.templates.spots.aws-ec2-spot-price", 0.5f);

        ClusterSpec spec = ClusterSpec.withTemporaryKeys(conf);
        List<InstanceTemplate> templates = spec.getInstanceTemplates();

        InstanceTemplate noops = get(templates, 0);
        assert noops.getRoles().contains("noop");
        assertEquals(noops.getHardwareId(), "m1.large");
        assertEquals(noops.getImageId(), null);

        InstanceTemplate second = get(templates, 1);
        assertEquals(second.getHardwareId(), "t1.micro");
        assertEquals(second.getImageId(), "us-east-1/ami-123324");

        InstanceTemplate third = get(templates, 2);
        assertEquals(third.getHardwareId(), null);
        assertEquals(third.getImageId(), null);

        InstanceTemplate spots = get(templates, 3);
        assertEquals(spots.getAwsEc2SpotPrice(), 0.5f, 0.001);
    }

    @Test(expected = ConfigurationException.class)
    public void testInstanceTemplateNotFoundForHardwareId() throws Exception {
        PropertiesConfiguration conf = new PropertiesConfiguration("whirr-core-test.properties");
        conf.setProperty("whirr.instance-templates", "1 role1+role2");
        conf.setProperty("whirr.templates.role1.hardware-id", "m1.large");

        ClusterSpec.withTemporaryKeys(conf);
    }

    @Test(expected = IllegalArgumentException.class)
    public void testFailIfRunningAsRootOrClusterUserIsRoot() throws ConfigurationException {
        PropertiesConfiguration conf = new PropertiesConfiguration("whirr-core-test.properties");
        conf.setProperty("whirr.cluster-user", "root");

        ClusterSpec.withNoDefaults(conf);
    }
}