org.jclouds.smartos.SmartOSHostController.java Source code

Java tutorial

Introduction

Here is the source code for org.jclouds.smartos.SmartOSHostController.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.jclouds.smartos;

import static com.google.common.base.Preconditions.checkNotNull;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.StringReader;
import java.net.URI;
import java.util.Map;
import java.util.UUID;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import javax.inject.Inject;

import org.jclouds.domain.Credentials;
import org.jclouds.domain.LoginCredentials;
import org.jclouds.json.Json;
import org.jclouds.location.Provider;
import org.jclouds.smartos.compute.domain.DataSet;
import org.jclouds.smartos.compute.domain.VM;
import org.jclouds.smartos.compute.domain.VmSpecification;
import org.jclouds.ssh.SshClient;

import com.google.common.base.Splitter;
import com.google.common.base.Supplier;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;
import com.google.common.net.HostAndPort;
import com.google.common.util.concurrent.RateLimiter;

/**
 * A host machine that runs smartOS
 */
public class SmartOSHostController {
    protected final String hostname;
    protected final Supplier<Credentials> creds;
    protected final SshClient.Factory sshClientFactory;
    protected final Json json;

    protected transient SshClient _connection;

    public static class HostException extends RuntimeException {

        public HostException(String s, Throwable throwable) {
            super(s, throwable);
        }

        public HostException(String s) {
            super(s);
        }
    }

    public static class NoResponseException extends Exception {

        public NoResponseException() {
        }
    }

    @Inject
    protected SmartOSHostController(@Provider Supplier<URI> provider,
            @org.jclouds.location.Provider final Supplier<Credentials> creds, SshClient.Factory sshFactory,
            Json json) {
        this.hostname = provider.get().getHost();
        this.creds = creds;
        this.sshClientFactory = sshFactory;
        this.json = json;
    }

    public String getDescription() {
        return "SmartOS@" + hostname;
    }

    public String getHostname() {
        return hostname;
    }

    public SshClient.Factory getSshClientFactory() {
        return sshClientFactory;
    }

    protected SshClient getConnection() {
        if (_connection == null) {
            Credentials currentCreds = checkNotNull(creds.get(), "credential supplier returned null");

            LoginCredentials credentials = new LoginCredentials.Builder().user(currentCreds.identity)
                    .password(currentCreds.credential).build();

            _connection = getSshClientFactory().create(HostAndPort.fromParts(hostname, 22), credentials);

            _connection.connect();

        }
        return _connection;
    }

    public String exec(String cmd) {
        return getConnection().exec(cmd).getOutput();
    }

    public String vmList() {
        return exec("vmadm list -p");
    }

    public Map<String, String> getVMIpAddresses(UUID vmId) {
        ImmutableMap.Builder<String, String> netMapBuilder = ImmutableMap.builder();

        String response = getConnection().exec("zlogin " + vmId.toString() + " ifconfig -a4").getOutput();

        if (response.length() == 0)
            return ImmutableMap.of();

        Iterable<String> strings = Splitter.on("\n").split(response);
        Pattern inetMatcher = Pattern.compile("inet [0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}");

        String iface = "";
        for (String line : strings) {
            if (line.length() > 0 && Character.isLetterOrDigit(line.charAt(0))) {
                iface = line.substring(0, line.indexOf(":"));
            } else {
                Matcher matcher = inetMatcher.matcher(line);
                if (matcher.find())
                    netMapBuilder.put(iface, matcher.group().substring(5));
            }
        }

        return netMapBuilder.build();

    }

    /**
     * What remotely available images are there in the cloud?
     * 
     * @return Collection of datasets
     */
    public Iterable<DataSet> getAvailableImages() {
        return toSpecList(exec("dsadm avail"));
    }

    public Iterable<DataSet> getLocalDatasets() {
        return toSpecList(exec("dsadm list"));
    }

    public Iterable<VM> getVMs() {
        return toVMList(exec("vmadm list -p"));
    }

    public VM createVM(VmSpecification specification) {

        String specAsJson = json.toJson(specification);
        String response = getConnection().exec("(cat <<END\n" + specAsJson + "\nEND\n) | vmadm create").getOutput();

        Pattern uuidPattern = Pattern.compile("[a-f0-9]{8}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{4}-[a-f0-9]{12}");
        Matcher matcher = uuidPattern.matcher(response);
        if (matcher.find()) {
            String uuid = matcher.group();
            return getVM(UUID.fromString(uuid));
        } else {
            throw new HostException("Error creating Host: response = " + response + "\n source = " + specAsJson);
        }

    }

    private Iterable<DataSet> toSpecList(String string) {

        try {
            BufferedReader r = new BufferedReader(new StringReader(string));
            r.readLine(); // Skip
            String line;
            ImmutableList.Builder<DataSet> resultBuilder = ImmutableList.builder();
            while ((line = r.readLine()) != null) {
                DataSet dataset = DataSet.builder().fromDsadmString(line).build();

                resultBuilder.add(dataset);
            }
            return resultBuilder.build();
        } catch (IOException e) {
            throw new HostException("Error parsing response when building spec list", e);
        }
    }

    private Iterable<VM> toVMList(String string) {
        try {
            BufferedReader r = new BufferedReader(new StringReader(string));
            String line;
            ImmutableList.Builder<VM> resultBuilder = ImmutableList.builder();
            while ((line = r.readLine()) != null) {
                VM vm = VM.builder().fromVmadmString(line).build();

                Map<String, String> ipAddresses;
                RateLimiter limiter = RateLimiter.create(1.0);
                for (int i = 0; i < 30; i++) {
                    ipAddresses = getVMIpAddresses(vm.getUuid());
                    if (!ipAddresses.isEmpty()) {
                        // Got some
                        String ip = ipAddresses.get("net0");
                        if (ip != null && !ip.equals("0.0.0.0")) {
                            vm = vm.toBuilder().publicAddress(ip).build();
                            break;
                        }
                    }

                    limiter.acquire();
                }

                resultBuilder.add(vm);
            }
            return resultBuilder.build();
        } catch (IOException e) {
            throw new HostException("Error parsing response when building VM list", e);
        }
    }

    public VM getVM(UUID serverId) {
        for (VM vm : getVMs())
            if (vm.getUuid().equals(serverId))
                return vm;
        return null;
    }

    public DataSet getDataSet(UUID imageId) {
        for (DataSet ds : getLocalDatasets()) {
            if (ds.getUuid().equals(imageId))
                return ds;
        }
        return null;
    }

    public void destroyHost(UUID uuid) {
        exec("vmadm delete " + uuid.toString());
    }

    public void rebootHost(UUID uuid) {
        exec("vmadm reboot " + uuid.toString());
    }

    public void stopHost(UUID uuid) {
        exec("vmadm stop -p");
    }

    public void startHost(UUID uuid) {
        exec("vmadm start " + uuid.toString());
    }
}