| 1 | /** | 
| 2 |  * | 
| 3 |  * Copyright (C) 2011 Cloud Conscious, LLC. <info@cloudconscious.com> | 
| 4 |  * | 
| 5 |  * ==================================================================== | 
| 6 |  * Licensed under the Apache License, Version 2.0 (the "License"); | 
| 7 |  * you may not use this file except in compliance with the License. | 
| 8 |  * You may obtain a copy of the License at | 
| 9 |  * | 
| 10 |  * http://www.apache.org/licenses/LICENSE-2.0 | 
| 11 |  * | 
| 12 |  * Unless required by applicable law or agreed to in writing, software | 
| 13 |  * distributed under the License is distributed on an "AS IS" BASIS, | 
| 14 |  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | 
| 15 |  * See the License for the specific language governing permissions and | 
| 16 |  * limitations under the License. | 
| 17 |  * ==================================================================== | 
| 18 |  */ | 
| 19 | package org.jclouds.compute.util; | 
| 20 |   | 
| 21 | import static com.google.common.base.Preconditions.checkState; | 
| 22 | import static com.google.common.base.Throwables.getStackTraceAsString; | 
| 23 | import static com.google.common.collect.Iterables.concat; | 
| 24 | import static com.google.common.collect.Iterables.filter; | 
| 25 | import static com.google.common.collect.Iterables.find; | 
| 26 | import static com.google.common.collect.Iterables.size; | 
| 27 | import static com.google.common.collect.Iterables.transform; | 
| 28 | import static org.jclouds.scriptbuilder.domain.Statements.pipeHttpResponseToBash; | 
| 29 |   | 
| 30 | import java.net.URI; | 
| 31 | import java.util.Formatter; | 
| 32 | import java.util.Map; | 
| 33 | import java.util.NoSuchElementException; | 
| 34 | import java.util.Map.Entry; | 
| 35 | import java.util.regex.Matcher; | 
| 36 | import java.util.regex.Pattern; | 
| 37 |   | 
| 38 | import org.jclouds.compute.ComputeServiceContextBuilder; | 
| 39 | import org.jclouds.compute.domain.ComputeMetadata; | 
| 40 | import org.jclouds.compute.domain.Hardware; | 
| 41 | import org.jclouds.compute.domain.NodeMetadata; | 
| 42 | import org.jclouds.compute.domain.OsFamily; | 
| 43 | import org.jclouds.compute.domain.Processor; | 
| 44 | import org.jclouds.compute.domain.Volume; | 
| 45 | import org.jclouds.compute.predicates.RetryIfSocketNotYetOpen; | 
| 46 | import org.jclouds.http.HttpRequest; | 
| 47 | import org.jclouds.net.IPSocket; | 
| 48 | import org.jclouds.rest.Providers; | 
| 49 | import org.jclouds.scriptbuilder.domain.Statement; | 
| 50 | import org.jclouds.scriptbuilder.domain.Statements; | 
| 51 |   | 
| 52 | import com.google.common.base.Function; | 
| 53 | import com.google.common.base.Predicate; | 
| 54 | import com.google.common.collect.Iterables; | 
| 55 |   | 
| 56 | /** | 
| 57 |  *  | 
| 58 |  * @author Adrian Cole | 
| 59 |  */ | 
| 60 | public class ComputeServiceUtils { | 
| 61 |    public static final Pattern DELIMETED_BY_HYPHEN_ENDING_IN_HYPHEN_HEX = Pattern.compile("(.+)-[0-9a-f]+"); | 
| 62 |   | 
| 63 |    /** | 
| 64 |     * build a shell script that invokes the contents of the http request in bash. | 
| 65 |     *  | 
| 66 |     * @return a shell script that will invoke the http request | 
| 67 |     */ | 
| 68 |    public static Statement execHttpResponse(HttpRequest request) { | 
| 69 |       return pipeHttpResponseToBash(request.getMethod(), request.getEndpoint(), request.getHeaders()); | 
| 70 |    } | 
| 71 |   | 
| 72 |    public static Statement execHttpResponse(URI location) { | 
| 73 |       return execHttpResponse(new HttpRequest("GET", location)); | 
| 74 |    } | 
| 75 |   | 
| 76 |    /** | 
| 77 |     * build a shell script that invokes the contents of the http request in bash. | 
| 78 |     *  | 
| 79 |     * @return a shell script that will invoke the http request | 
| 80 |     */ | 
| 81 |    public static Statement extractTargzIntoDirectory(HttpRequest targz, String directory) { | 
| 82 |       return Statements | 
| 83 |                .extractTargzIntoDirectory(targz.getMethod(), targz.getEndpoint(), targz.getHeaders(), directory); | 
| 84 |    } | 
| 85 |   | 
| 86 |    public static Statement extractTargzIntoDirectory(URI targz, String directory) { | 
| 87 |       return extractTargzIntoDirectory(new HttpRequest("GET", targz), directory); | 
| 88 |    } | 
| 89 |   | 
| 90 |    /** | 
| 91 |     * build a shell script that invokes the contents of the http request in bash. | 
| 92 |     *  | 
| 93 |     * @return a shell script that will invoke the http request | 
| 94 |     */ | 
| 95 |    public static Statement extractZipIntoDirectory(HttpRequest zip, String directory) { | 
| 96 |       return Statements.extractZipIntoDirectory(zip.getMethod(), zip.getEndpoint(), zip.getHeaders(), directory); | 
| 97 |    } | 
| 98 |   | 
| 99 |    public static Statement extractZipIntoDirectory(URI zip, String directory) { | 
| 100 |       return extractZipIntoDirectory(new HttpRequest("GET", zip), directory); | 
| 101 |    } | 
| 102 |   | 
| 103 |    /** | 
| 104 |     *  | 
| 105 |     * @return null if group cannot be parsed | 
| 106 |     */ | 
| 107 |    public static String parseGroupFromName(String from) { | 
| 108 |       Matcher matcher = DELIMETED_BY_HYPHEN_ENDING_IN_HYPHEN_HEX.matcher(from); | 
| 109 |       return matcher.find() ? matcher.group(1) : null; | 
| 110 |    } | 
| 111 |   | 
| 112 |    public static double getCores(Hardware input) { | 
| 113 |       double cores = 0; | 
| 114 |       for (Processor processor : input.getProcessors()) | 
| 115 |          cores += processor.getCores(); | 
| 116 |       return cores; | 
| 117 |    } | 
| 118 |   | 
| 119 |    public static double getCoresAndSpeed(Hardware input) { | 
| 120 |       double total = 0; | 
| 121 |       for (Processor processor : input.getProcessors()) | 
| 122 |          total += (processor.getCores() * processor.getSpeed()); | 
| 123 |       return total; | 
| 124 |    } | 
| 125 |   | 
| 126 |    public static double getSpace(Hardware input) { | 
| 127 |       double total = 0; | 
| 128 |       for (Volume volume : input.getVolumes()) | 
| 129 |          total += volume.getSize() != null ? volume.getSize() : 0; | 
| 130 |       return total; | 
| 131 |    } | 
| 132 |   | 
| 133 |    public static org.jclouds.compute.domain.OsFamily parseOsFamilyOrUnrecognized(String in) { | 
| 134 |       org.jclouds.compute.domain.OsFamily myOs = null; | 
| 135 |       for (org.jclouds.compute.domain.OsFamily os : org.jclouds.compute.domain.OsFamily.values()) { | 
| 136 |          if (in.toLowerCase().replaceAll("\\s", "").indexOf(os.toString()) != -1) { | 
| 137 |             myOs = os; | 
| 138 |          } | 
| 139 |       } | 
| 140 |       return myOs != null ? myOs : OsFamily.UNRECOGNIZED; | 
| 141 |    } | 
| 142 |   | 
| 143 |    public static String createExecutionErrorMessage(Map<?, Exception> executionExceptions) { | 
| 144 |       Formatter fmt = new Formatter().format("Execution failures:%n%n"); | 
| 145 |       int index = 1; | 
| 146 |       for (Entry<?, Exception> errorMessage : executionExceptions.entrySet()) { | 
| 147 |          fmt.format("%s) %s on %s:%n%s%n%n", index++, errorMessage.getValue().getClass().getSimpleName(), errorMessage | 
| 148 |                   .getKey(), getStackTraceAsString(errorMessage.getValue())); | 
| 149 |       } | 
| 150 |       return fmt.format("%s error[s]", executionExceptions.size()).toString(); | 
| 151 |    } | 
| 152 |   | 
| 153 |    public static String createNodeErrorMessage(Map<? extends NodeMetadata, ? extends Throwable> failedNodes) { | 
| 154 |       Formatter fmt = new Formatter().format("Node failures:%n%n"); | 
| 155 |       int index = 1; | 
| 156 |       for (Entry<? extends NodeMetadata, ? extends Throwable> errorMessage : failedNodes.entrySet()) { | 
| 157 |          fmt.format("%s) %s on node %s:%n%s%n%n", index++, errorMessage.getValue().getClass().getSimpleName(), | 
| 158 |                   errorMessage.getKey().getId(), getStackTraceAsString(errorMessage.getValue())); | 
| 159 |       } | 
| 160 |       return fmt.format("%s error[s]", failedNodes.size()).toString(); | 
| 161 |    } | 
| 162 |   | 
| 163 |    public static Iterable<? extends ComputeMetadata> filterByName(Iterable<? extends ComputeMetadata> nodes, | 
| 164 |             final String name) { | 
| 165 |       return filter(nodes, new Predicate<ComputeMetadata>() { | 
| 166 |          @Override | 
| 167 |          public boolean apply(ComputeMetadata input) { | 
| 168 |             return input.getName().equalsIgnoreCase(name); | 
| 169 |          } | 
| 170 |       }); | 
| 171 |    } | 
| 172 |   | 
| 173 |    public static Iterable<String> getSupportedProviders() { | 
| 174 |       return Providers.getSupportedProvidersOfType(ComputeServiceContextBuilder.class); | 
| 175 |    } | 
| 176 |   | 
| 177 |    public static IPSocket findReachableSocketOnNode(RetryIfSocketNotYetOpen socketTester, final NodeMetadata node, | 
| 178 |             final int port) { | 
| 179 |       checkNodeHasIps(node); | 
| 180 |       IPSocket socket = null; | 
| 181 |       try { | 
| 182 |          socket = find(transform(concat(node.getPublicAddresses(), node.getPrivateAddresses()), | 
| 183 |                   new Function<String, IPSocket>() { | 
| 184 |   | 
| 185 |                      @Override | 
| 186 |                      public IPSocket apply(String from) { | 
| 187 |                         return new IPSocket(from, port); | 
| 188 |                      } | 
| 189 |                   }), socketTester); | 
| 190 |       } catch (NoSuchElementException e) { | 
| 191 |          throw new NoSuchElementException(String.format("could not connect to any ip address port %d on node %s", port, | 
| 192 |                   node)); | 
| 193 |       } | 
| 194 |       return socket; | 
| 195 |    } | 
| 196 |   | 
| 197 |    public static void checkNodeHasIps(NodeMetadata node) { | 
| 198 |       checkState(size(concat(node.getPublicAddresses(), node.getPrivateAddresses())) > 0, | 
| 199 |                "node does not have IP addresses configured: " + node); | 
| 200 |    } | 
| 201 |   | 
| 202 |    public static String parseVersionOrReturnEmptyString(org.jclouds.compute.domain.OsFamily family, String in, | 
| 203 |             Map<OsFamily, Map<String, String>> osVersionMap) { | 
| 204 |       if (osVersionMap.containsKey(family)) { | 
| 205 |          if (osVersionMap.get(family).containsKey(in)) | 
| 206 |             return osVersionMap.get(family).get(in); | 
| 207 |          if (osVersionMap.get(family).containsValue(in)) | 
| 208 |             return in; | 
| 209 |          CONTAINS_SUBSTRING contains = new CONTAINS_SUBSTRING(in.replace('-', '.')); | 
| 210 |          try { | 
| 211 |             String key = Iterables.find(osVersionMap.get(family).keySet(), contains); | 
| 212 |             return osVersionMap.get(family).get(key); | 
| 213 |          } catch (NoSuchElementException e) { | 
| 214 |             try { | 
| 215 |                return Iterables.find(osVersionMap.get(family).values(), contains); | 
| 216 |             } catch (NoSuchElementException e1) { | 
| 217 |             } | 
| 218 |          } | 
| 219 |       } | 
| 220 |       return ""; | 
| 221 |    } | 
| 222 |   | 
| 223 |    static final class CONTAINS_SUBSTRING implements Predicate<String> { | 
| 224 |       private final String in; | 
| 225 |   | 
| 226 |       CONTAINS_SUBSTRING(String in) { | 
| 227 |          this.in = in; | 
| 228 |       } | 
| 229 |   | 
| 230 |       @Override | 
| 231 |       public boolean apply(String input) { | 
| 232 |          return in.indexOf(input) != -1; | 
| 233 |       } | 
| 234 |    } | 
| 235 |   | 
| 236 | } |