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 }