Coverage Report - com.thindeck.agents.Script
 
Classes in this File Line Coverage Branch Coverage Complexity
Script
N/A
N/A
1
Script$Default
0%
0/10
N/A
1
Script$Default$1
0%
0/2
N/A
1
Script$Fake
100%
5/5
N/A
1
 
 1  2
 /**
 2  
  * Copyright (c) 2014-2015, Thindeck.com
 3  
  * All rights reserved.
 4  
  *
 5  
  * Redistribution and use in source and binary forms, with or without
 6  
  * modification, are permitted provided that the following conditions
 7  
  * are met: 1) Redistributions of source code must retain the above
 8  
  * copyright notice, this list of conditions and the following
 9  
  * disclaimer. 2) Redistributions in binary form must reproduce the above
 10  
  * copyright notice, this list of conditions and the following
 11  
  * disclaimer in the documentation and/or other materials provided
 12  
  * with the distribution. 3) Neither the name of the thindeck.com nor
 13  
  * the names of its contributors may be used to endorse or promote
 14  
  * products derived from this software without specific prior written
 15  
  * permission.
 16  
  *
 17  
  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
 18  
  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT
 19  
  * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
 20  
  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 21  
  * THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
 22  
  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 23  
  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 24  
  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 25  
  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
 26  
  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 27  
  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
 28  
  * OF THE POSSIBILITY OF SUCH DAMAGE.
 29  
  */
 30  
 package com.thindeck.agents;
 31  
 
 32  
 import com.google.common.base.Charsets;
 33  
 import com.google.common.base.Function;
 34  
 import com.google.common.base.Joiner;
 35  
 import com.google.common.collect.Iterables;
 36  
 import com.jcabi.aspects.Immutable;
 37  
 import com.jcabi.ssh.SSH;
 38  
 import com.jcabi.ssh.Shell;
 39  
 import java.io.ByteArrayOutputStream;
 40  
 import java.io.IOException;
 41  
 import java.net.URL;
 42  
 import java.util.Arrays;
 43  
 import java.util.Map;
 44  
 import org.apache.commons.io.IOUtils;
 45  
 import org.apache.commons.io.output.NullOutputStream;
 46  
 
 47  
 /**
 48  
  * Execs a script.
 49  
  *
 50  
  * @author Yegor Bugayenko (yegor@teamed.io)
 51  
  * @version $Id$
 52  
  * @since 0.1
 53  
  */
 54  
 @Immutable
 55  
 public interface Script {
 56  
 
 57  
     /**
 58  
      * Run it.
 59  
      * @param host The host to run it on
 60  
      * @param args Arguments to pass into it
 61  
      * @return Stdout
 62  
      * @throws IOException If fails
 63  
      */
 64  
     String exec(String host, Map<String, String> args)
 65  
         throws IOException;
 66  
 
 67  
     /**
 68  
      * Default one.
 69  
      */
 70  
     @Immutable
 71  
     final class Default implements Script {
 72  
         /**
 73  
          * Script.
 74  
          */
 75  
         private final transient String script;
 76  
         /**
 77  
          * Ctor.
 78  
          * @param url Resource URL
 79  
          * @throws IOException If fails
 80  
          */
 81  
         public Default(final URL url) throws IOException {
 82  0
             this(IOUtils.toString(url.openStream()));
 83  0
         }
 84  
         /**
 85  
          * Ctor.
 86  
          * @param text Content of script
 87  
          */
 88  0
         public Default(final String text) {
 89  0
             this.script = text;
 90  0
         }
 91  
         @Override
 92  
         public String exec(final String host, final Map<String, String> args)
 93  
             throws IOException {
 94  0
             final String command = Joiner.on(" && ").join(
 95  
                 Iterables.concat(
 96  
                     Arrays.asList(
 97  
                         "dir=$(mktemp -d -t td-XXXX)",
 98  
                         "cd \"${dir}\"",
 99  
                         "cat > script.sh",
 100  
                         "chmod a+x script.sh"
 101  
                     ),
 102  
                     Iterables.transform(
 103  
                         args.entrySet(),
 104  0
                         new Function<Map.Entry<String, String>, String>() {
 105  
                             @Override
 106  
                             public String apply(
 107  
                                 final Map.Entry<String, String> ent) {
 108  0
                                 return String.format(
 109  
                                     "export %s=%s",
 110  
                                     ent.getKey(), SSH.escape(ent.getValue())
 111  
                                 );
 112  
                             }
 113  
                         }
 114  
                     ),
 115  
                     Arrays.asList(
 116  
                         "./script.sh %s",
 117  
                         "rm -rf \"${dir}\""
 118  
                     )
 119  
                 )
 120  
             );
 121  0
             final ByteArrayOutputStream baos = new ByteArrayOutputStream();
 122  0
             new Shell.Safe(new Shell.Safe(new Remote(host))).exec(
 123  
                 command,
 124  
                 IOUtils.toInputStream(this.script),
 125  
                 baos,
 126  
                 new NullOutputStream()
 127  
             );
 128  0
             return new String(baos.toByteArray(), Charsets.UTF_8);
 129  
         }
 130  
     }
 131  
 
 132  
     /**
 133  
      * Fake one.
 134  
      */
 135  
     @Immutable
 136  
     final class Fake implements Script {
 137  
         /**
 138  
          * Stdout.
 139  
          */
 140  
         private final transient String stdout;
 141  
         /**
 142  
          * Ctor.
 143  
          * @param txt Text of stdout
 144  
          */
 145  6
         public Fake(final String txt) {
 146  6
             this.stdout = txt;
 147  6
         }
 148  
         @Override
 149  
         public String exec(final String host, final Map<String, String> args) {
 150  1
             return this.stdout;
 151  
         }
 152  
     }
 153  
 }