github.com/cloud-green/juju@v0.0.0-20151002100041-a00291338d3d/provider/vsphere/ssh_client.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // +build !gccgo
     5  
     6  package vsphere
     7  
     8  import (
     9  	"fmt"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/juju/errors"
    14  
    15  	"github.com/juju/juju/network"
    16  	"github.com/juju/juju/utils/ssh"
    17  )
    18  
    19  type sshClient struct {
    20  	client  ssh.Client
    21  	host    string
    22  	options *ssh.Options
    23  }
    24  
    25  func newSshClient(host string) *sshClient {
    26  	options := ssh.Options{}
    27  	options.SetIdentities("/var/lib/juju/system-identity")
    28  	return &sshClient{
    29  		client:  ssh.DefaultClient,
    30  		host:    "ubuntu@" + host,
    31  		options: &options,
    32  	}
    33  }
    34  
    35  func (c *sshClient) configureExternalIpAddress(apiPort int) error {
    36  	cmd := `printf 'auto eth1\niface eth1 inet dhcp' | sudo tee -a /etc/network/interfaces.d/eth1.cfg
    37  sudo ifup eth1
    38  sudo iptables -i eth1 -I INPUT -j DROP`
    39  
    40  	if apiPort > 0 {
    41  		cmd += fmt.Sprintf("\nsudo iptables -I INPUT -p tcp --dport %d -j ACCEPT", apiPort)
    42  	}
    43  
    44  	command := c.client.Command(c.host, []string{"/bin/bash"}, c.options)
    45  	command.Stdin = strings.NewReader(cmd)
    46  	output, err := command.CombinedOutput()
    47  	if err != nil {
    48  		return errors.Errorf("failed to allocate external IP address: %s", output)
    49  	}
    50  	logger.Tracef("configure external ip address output: %s", output)
    51  	return nil
    52  }
    53  
    54  func (c *sshClient) changePorts(ipAddress string, insert bool, ports []network.PortRange) error {
    55  	cmd := ""
    56  	insertArg := "-I"
    57  	if !insert {
    58  		insertArg = "-D"
    59  	}
    60  	for _, port := range ports {
    61  		if port.ToPort-port.FromPort > 0 {
    62  			cmd += fmt.Sprintf("sudo iptables -d %s %s INPUT -p %s --match multiport --dports %d:%d -j ACCEPT\n", ipAddress, insertArg, port.Protocol, port.FromPort, port.ToPort)
    63  		} else {
    64  
    65  			cmd += fmt.Sprintf("sudo iptables -d %s %s INPUT -p %s --dport %d -j ACCEPT\n", ipAddress, insertArg, port.Protocol, port.FromPort)
    66  		}
    67  	}
    68  	cmd += "sudo /etc/init.d/iptables-persistent save\n"
    69  	command := c.client.Command(c.host, []string{"/bin/bash"}, c.options)
    70  	command.Stdin = strings.NewReader(cmd)
    71  	output, err := command.CombinedOutput()
    72  	if err != nil {
    73  		return errors.Errorf("failed to configure ports on external network: %s", output)
    74  	}
    75  	logger.Tracef("change ports output: %s", output)
    76  	return nil
    77  }
    78  
    79  func (c *sshClient) findOpenPorts() ([]network.PortRange, error) {
    80  	cmd := "sudo iptables -L INPUT -n"
    81  	command := c.client.Command(c.host, []string{"/bin/bash"}, c.options)
    82  	command.Stdin = strings.NewReader(cmd)
    83  	output, err := command.CombinedOutput()
    84  	if err != nil {
    85  		return nil, errors.Errorf("failed to list open ports: %s", output)
    86  	}
    87  	logger.Tracef("find open ports output: %s", output)
    88  
    89  	//the output have the following format, we will skipp all other rules
    90  	//Chain INPUT (policy ACCEPT)
    91  	//target     prot opt source               destination
    92  	//ACCEPT     tcp  --  0.0.0.0/0            192.168.0.1  multiport dports 3456:3458
    93  	//ACCEPT     tcp  --  0.0.0.0/0            192.168.0.2  tcp dpt:12345
    94  
    95  	res := make([]network.PortRange, 0)
    96  	var addSinglePortRange = func(items []string) {
    97  		ports := strings.Split(items[6], ":")
    98  		if len(ports) != 2 {
    99  			return
   100  		}
   101  		to, err := strconv.ParseInt(ports[1], 10, 32)
   102  		if err != nil {
   103  			return
   104  		}
   105  
   106  		res = append(res, network.PortRange{
   107  			Protocol: items[1],
   108  			FromPort: int(to),
   109  			ToPort:   int(to),
   110  		})
   111  	}
   112  	var addMultiplePortRange = func(items []string) {
   113  		ports := strings.Split(items[7], ":")
   114  		if len(ports) != 2 {
   115  			return
   116  		}
   117  		from, err := strconv.ParseInt(ports[0], 10, 32)
   118  		if err != nil {
   119  			return
   120  		}
   121  		to, err := strconv.ParseInt(ports[1], 10, 32)
   122  		if err != nil {
   123  			return
   124  		}
   125  
   126  		res = append(res, network.PortRange{
   127  			Protocol: items[1],
   128  			FromPort: int(from),
   129  			ToPort:   int(to),
   130  		})
   131  	}
   132  
   133  	for i, line := range strings.Split(string(output), "\n") {
   134  		if i == 1 || i == 0 {
   135  			continue
   136  		}
   137  		items := strings.Split(line, " ")
   138  		if len(items) == 7 && items[0] == "ACCEPT" && items[3] == "0.0.0.0/0" {
   139  			addSinglePortRange(items)
   140  		}
   141  		if len(items) == 8 && items[0] == "ACCEPT" && items[3] == "0.0.0.0/0" && items[5] != "multiport" && items[6] != "dports" {
   142  			addMultiplePortRange(items)
   143  		}
   144  	}
   145  	return res, nil
   146  }
   147  
   148  func (c *sshClient) addIpAddress(nic string, addr string) error {
   149  	cmd := fmt.Sprintf("ls /etc/network/interfaces.d | grep %s: | sed 's/%s://' | sed 's/.cfg//' | tail -1", nic, nic)
   150  	command := c.client.Command(c.host, []string{"/bin/bash"}, c.options)
   151  	command.Stdin = strings.NewReader(cmd)
   152  	lastIndStr, err := command.CombinedOutput()
   153  	if err != nil {
   154  		return errors.Errorf("failed to obtain last device index: %s", lastIndStr)
   155  	}
   156  	lastInd := 0
   157  	if ind, err := strconv.ParseInt(string(lastIndStr), 10, 64); err != nil {
   158  		lastInd = int(ind) + 1
   159  	}
   160  	nic = fmt.Sprintf("%s:%d", nic, lastInd)
   161  	cmd = fmt.Sprintf("printf 'auto %s\\niface %s inet static\\naddress %s' | sudo tee -a /etc/network/interfaces.d/%s.cfg\nsudo ifup %s", nic, nic, addr, nic, nic)
   162  
   163  	command = c.client.Command(c.host, []string{"/bin/bash"}, c.options)
   164  	command.Stdin = strings.NewReader(cmd)
   165  	output, err := command.CombinedOutput()
   166  	if err != nil {
   167  		return errors.Errorf("failed to add IP address: %s", output)
   168  	}
   169  	logger.Tracef("add ip address output: %s", output)
   170  	return nil
   171  }
   172  
   173  func (c *sshClient) releaseIpAddress(_ string, addr string) error {
   174  	cmd := fmt.Sprintf("ip addr show | grep %s | awk '{print $7}'", addr)
   175  	command := c.client.Command(c.host, []string{"/bin/bash"}, c.options)
   176  	command.Stdin = strings.NewReader(cmd)
   177  	nic, err := command.CombinedOutput()
   178  	if err != nil {
   179  		return errors.Errorf("faild to get nic by ip address: %s", nic)
   180  	}
   181  
   182  	cmd = fmt.Sprintf("sudo rm %s.cfg \nsudo ifdown %s", nic, nic)
   183  	command = c.client.Command(c.host, []string{"/bin/bash"}, c.options)
   184  	command.Stdin = strings.NewReader(cmd)
   185  	output, err := command.CombinedOutput()
   186  	if err != nil {
   187  		return errors.Errorf("failed to release IP address: %s", output)
   188  	}
   189  	logger.Tracef("release ip address output: %s", output)
   190  	return nil
   191  }