func getRegistryClient() (client.API, error) { var dial func(string, string) (net.Conn, error) tun := getTunnelFlag() if tun != "" { sshClient, err := ssh.NewSSHClient("core", tun, getChecker(), false) if err != nil { return nil, fmt.Errorf("failed initializing SSH client: %v", err) } dial = func(network, addr string) (net.Conn, error) { tcpaddr, err := net.ResolveTCPAddr(network, addr) if err != nil { return nil, err } return sshClient.DialTCP(network, nil, tcpaddr) } } trans := http.Transport{ Dial: dial, TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, } return client.NewRegistryClient(&trans, globalFlags.Endpoint, globalFlags.EtcdKeyPrefix) }
func getRegistry() *registry.Registry { tun := getTunnelFlag() endpoint := getEndpointFlag() machines := []string{endpoint} client := etcd.NewClient(machines) if tun != "" { sshClient, err := ssh.NewSSHClient("core", tun, getChecker(), false) if err != nil { log.Fatalf("Failed initializing SSH client: %v", err) } dial := func(network, addr string) (net.Conn, error) { tcpaddr, err := net.ResolveTCPAddr(network, addr) if err != nil { return nil, err } return sshClient.DialTCP(network, nil, tcpaddr) } tr := http.Transport{ Dial: dial, TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, } client.SetTransport(&tr) } return registry.New(client) }
func getRegistry(context *cli.Context) *registry.Registry { tun := getTunnelFlag(context) endpoint := context.GlobalString("endpoint") machines := []string{endpoint} client := etcd.NewClient(machines) if tun != "" { sshClient, err := ssh.NewSSHClient("core", tun) if err != nil { panic(err) } dial := func(network, addr string) (net.Conn, error) { tcpaddr, err := net.ResolveTCPAddr(network, addr) if err != nil { return nil, err } return sshClient.DialTCP(network, nil, tcpaddr) } tr := http.Transport{ Dial: dial, TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, } client.SetTransport(&tr) } return registry.New(client) }
// getRegistry initializes a connection to the Registry func getRegistry() registry.Registry { tun := getTunnelFlag() machines := []string{globalFlags.Endpoint} client := etcd.NewClient(machines) if tun != "" { sshClient, err := ssh.NewSSHClient("core", tun, getChecker(), false) if err != nil { fmt.Fprintf(os.Stderr, "Failed initializing SSH client: %v\n", err) os.Exit(1) } dial := func(network, addr string) (net.Conn, error) { tcpaddr, err := net.ResolveTCPAddr(network, addr) if err != nil { return nil, err } return sshClient.DialTCP(network, nil, tcpaddr) } tr := http.Transport{ Dial: dial, TLSClientConfig: &tls.Config{ InsecureSkipVerify: true, }, } client.SetTransport(&tr) } return registry.New(client, globalFlags.EtcdKeyPrefix) }
func runSSH(args []string) (exit int) { if flagUnit != "" && flagMachine != "" { fmt.Fprintln(os.Stderr, "Both machine and unit flags provided, please specify only one.") return 1 } var err error var addr string switch { case flagMachine != "": addr, _ = findAddressInMachineList(flagMachine) case flagUnit != "": addr, _ = findAddressInRunningUnits(flagUnit) default: addr, err = globalMachineLookup(args) if err != nil { fmt.Fprintln(os.Stderr, err) return 1 } // trim machine/unit name from args if len(args) > 0 { args = args[1:] } } if addr == "" { fmt.Fprintln(os.Stderr, "Requested machine could not be found.") return 1 } args = pkg.TrimToDashes(args) var sshClient *ssh.SSHForwardingClient if tun := getTunnelFlag(); tun != "" { sshClient, err = ssh.NewTunnelledSSHClient("core", tun, addr, getChecker(), flagSSHAgentForwarding) } else { sshClient, err = ssh.NewSSHClient("core", addr, getChecker(), flagSSHAgentForwarding) } if err != nil { fmt.Fprintf(os.Stderr, "Failed building SSH client: %v\n", err) return 1 } defer sshClient.Close() if len(args) > 0 { cmd := strings.Join(args, " ") err, exit = ssh.Execute(sshClient, cmd) if err != nil { fmt.Fprintf(os.Stderr, "Failed running command over SSH: %v\n", err) } } else { if err := ssh.Shell(sshClient); err != nil { fmt.Fprintf(os.Stderr, "Failed opening shell over SSH: %v\n", err) exit = 1 } } return }
func printUnitStatus(c *cli.Context, jobName string) { js := registryCtl.GetJobState(jobName) if js == nil { fmt.Printf("%s does not appear to be running\n", jobName) syscall.Exit(1) } addr := fmt.Sprintf("%s:22", js.MachineState.PublicIP) var err error var sshClient *ssh.SSHForwardingClient if tun := getTunnelFlag(); tun != "" { sshClient, err = ssh.NewTunnelledSSHClient("core", tun, addr, getChecker(), false) } else { sshClient, err = ssh.NewSSHClient("core", addr, getChecker(), false) } if err != nil { log.Fatal(err.Error()) } defer sshClient.Close() cmd := fmt.Sprintf("systemctl status -l %s", jobName) channel, err := ssh.Execute(sshClient, cmd) if err != nil { log.Fatalf("Unable to execute command over SSH: %s", err.Error()) } readSSHChannel(channel) }
func getRegistryClient() (client.API, error) { var dial func(string, string) (net.Conn, error) tun := getTunnelFlag() if tun != "" { sshClient, err := ssh.NewSSHClient("core", tun, getChecker(), false) if err != nil { return nil, fmt.Errorf("failed initializing SSH client: %v", err) } dial = func(network, addr string) (net.Conn, error) { tcpaddr, err := net.ResolveTCPAddr(network, addr) if err != nil { return nil, err } return sshClient.DialTCP(network, nil, tcpaddr) } } tlsConfig, err := etcd.ReadTLSConfigFiles(globalFlags.EtcdCAFile, globalFlags.EtcdCertFile, globalFlags.EtcdKeyFile) if err != nil { return nil, err } trans := http.Transport{ Dial: dial, TLSClientConfig: tlsConfig, } timeout := time.Duration(globalFlags.RequestTimeout*1000) * time.Millisecond return client.NewRegistryClient(&trans, globalFlags.Endpoint, globalFlags.EtcdKeyPrefix, timeout) }
func sshAction(c *cli.Context) { unit := c.String("unit") machine := c.String("machine") if unit != "" && machine != "" { log.Fatal("Both flags, machine and unit provided, please specify only one") } args := c.Args() var err error var addr string switch { case machine != "": addr, _ = findAddressInMachineList(machine) case unit != "": addr, _ = findAddressInRunningUnits(unit) default: addr, err = globalMachineLookup(args) args = args[1:] } if err != nil { log.Fatal(err) } if addr == "" { log.Fatalf("Requested machine could not be found") } agentForwarding := c.Bool("agent") var sshClient *ssh.SSHForwardingClient if tun := getTunnelFlag(); tun != "" { sshClient, err = ssh.NewTunnelledSSHClient("core", tun, addr, getChecker(), agentForwarding) } else { sshClient, err = ssh.NewSSHClient("core", addr, getChecker(), agentForwarding) } if err != nil { log.Fatal(err.Error()) return } defer sshClient.Close() if len(args) > 0 { cmd := strings.Join(args, " ") channel, err := ssh.Execute(sshClient, cmd) if err != nil { log.Fatalf("Unable to run command over SSH: %s", err.Error()) } readSSHChannel(channel) } else { if err := ssh.Shell(sshClient); err != nil { log.Fatalf(err.Error()) } } }
func getRegistryClient(cCmd *cobra.Command) (client.API, error) { var dial func(string, string) (net.Conn, error) SSHUserName, _ := cmdFleet.PersistentFlags().GetString("ssh-username") tun := getTunnelFlag(cCmd) if tun != "" { sshClient, err := ssh.NewSSHClient(SSHUserName, tun, getChecker(cCmd), false, getSSHTimeoutFlag(cCmd)) if err != nil { return nil, fmt.Errorf("failed initializing SSH client: %v", err) } dial = func(network, addr string) (net.Conn, error) { tcpaddr, err := net.ResolveTCPAddr(network, addr) if err != nil { return nil, err } return sshClient.DialTCP(network, nil, tcpaddr) } } CAFile, _ := cmdFleet.PersistentFlags().GetString("ca-file") CertFile, _ := cmdFleet.PersistentFlags().GetString("cert-file") KeyFile, _ := cmdFleet.PersistentFlags().GetString("key-file") tlsConfig, err := pkg.ReadTLSConfigFiles(CAFile, CertFile, KeyFile) if err != nil { return nil, err } trans := &http.Transport{ Dial: dial, TLSClientConfig: tlsConfig, } endPoint, _ := cmdFleet.PersistentFlags().GetString("endpoint") eCfg := etcd.Config{ Endpoints: strings.Split(endPoint, ","), Transport: trans, HeaderTimeoutPerRequest: getRequestTimeoutFlag(cCmd), } eClient, err := etcd.New(eCfg) if err != nil { return nil, err } etcdKeyPrefix, _ := cmdFleet.PersistentFlags().GetString("etcd-key-prefix") kAPI := etcd.NewKeysAPI(eClient) reg := registry.NewEtcdRegistry(kAPI, etcdKeyPrefix) if msg, ok := checkVersion(reg); !ok { stderr(msg) } return &client.RegistryClient{Registry: reg}, nil }
func journalAction(c *cli.Context) { if len(c.Args()) != 1 { fmt.Println("One unit file must be provided.") syscall.Exit(1) } jobName := c.Args()[0] js := registryCtl.GetJobState(jobName) if js == nil { fmt.Printf("%s does not appear to be running\n", jobName) syscall.Exit(1) } addr := fmt.Sprintf("%s:22", js.MachineState.PublicIP) var err error var sshClient *gossh.ClientConn if tun := getTunnelFlag(); tun != "" { sshClient, err = ssh.NewTunnelledSSHClient("core", tun, addr) } else { sshClient, err = ssh.NewSSHClient("core", addr) } if err != nil { log.Fatal(err.Error()) } defer sshClient.Close() cmd := fmt.Sprintf("journalctl -u %s --no-pager -l -n %d", jobName, c.Int("lines")) if c.Bool("follow") { cmd += " -f" } stdout, err := ssh.Execute(sshClient, cmd) if err != nil { log.Fatalf("Unable to run command over SSH: %s", err.Error()) } for true { bytes, prefix, err := stdout.ReadLine() if err != nil { break } fmt.Print(string(bytes)) if !prefix { fmt.Print("\n") } } }
// runRemoteCommand runs the given command over SSH on the given IP, and returns // any error encountered and the exit status of the command func runRemoteCommand(cmd string, addr string) (err error, exit int) { var sshClient *ssh.SSHForwardingClient if tun := getTunnelFlag(); tun != "" { sshClient, err = ssh.NewTunnelledSSHClient("core", tun, addr, getChecker(), false) } else { sshClient, err = ssh.NewSSHClient("core", addr, getChecker(), false) } if err != nil { return err, -1 } defer sshClient.Close() return ssh.Execute(sshClient, cmd) }
func getRegistryClient(config FleetConfig) (client.API, error) { var dial func(string, string) (net.Conn, error) tun := config.Tunnel if tun != "" { sshClient, err := ssh.NewSSHClient(config.SSHUserName, tun, getChecker(config), false, config.SSHTimeout) if err != nil { return nil, fmt.Errorf("failed initializing SSH client: %v", err) } dial = func(network, addr string) (net.Conn, error) { tcpaddr, err := net.ResolveTCPAddr(network, addr) if err != nil { return nil, err } return sshClient.DialTCP(network, nil, tcpaddr) } } tlsConfig, err := pkg.ReadTLSConfigFiles(config.CAFile, config.CertFile, config.KeyFile) if err != nil { return nil, err } trans := &http.Transport{ Dial: dial, TLSClientConfig: tlsConfig, } eCfg := etcd.Config{ Endpoints: strings.Split(config.EndPoint, ","), Transport: trans, HeaderTimeoutPerRequest: config.RequestTimeout, } eClient, err := etcd.New(eCfg) if err != nil { return nil, err } kAPI := etcd.NewKeysAPI(eClient) reg := registry.NewEtcdRegistry(kAPI, config.EtcdKeyPrefix) /*if msg, ok := checkVersion(reg); !ok { stderr(msg) }*/ return &client.RegistryClient{Registry: reg}, nil }
// runRemoteCommand runs the given command over SSH on the given IP, and returns // any error encountered and the exit status of the command func runRemoteCommand(cmd string, addr string, timeout time.Duration) (exit int, err error) { var sshClient *ssh.SSHForwardingClient if tun := getTunnelFlag(); tun != "" { sshClient, err = ssh.NewTunnelledSSHClient("core", tun, addr, getChecker(), false, timeout) } else { sshClient, err = ssh.NewSSHClient("core", addr, getChecker(), false, timeout) } if err != nil { return -1, err } defer sshClient.Close() err, exit = ssh.Execute(sshClient, cmd) return }
// runRemoteCommand runs the given command over SSH on the given IP, and returns // any error encountered and the exit status of the command func runRemoteCommand(cmd string, addr string) (err error, exit int) { var sshClient *ssh.SSHForwardingClient timeout := getSSHTimeoutFlag() if tun := getTunnelFlag(); tun != "" { sshClient, err = ssh.NewTunnelledSSHClient(globalFlags.SSHUserName, tun, addr, getChecker(), false, timeout) } else { sshClient, err = ssh.NewSSHClient(globalFlags.SSHUserName, addr, getChecker(), false, timeout) } if err != nil { return err, -1 } defer sshClient.Close() return ssh.Execute(sshClient, cmd) }
// SSH opens an interactive shell to a machine in the cluster func (c *FleetClient) SSH(name string) (err error) { var sshClient *ssh.SSHForwardingClient timeout := time.Duration(Flags.SSHTimeout*1000) * time.Millisecond ms, err := c.machineState(name) if err != nil { return err } // If name isn't a machine ID, try it as a unit instead if ms == nil { units, err := c.Units(name) if err != nil { return err } machID, err := c.findUnit(units[0]) if err != nil { return err } ms, err = c.machineState(machID) if err != nil || ms == nil { return err } } addr := ms.PublicIP if tun := getTunnelFlag(); tun != "" { sshClient, err = ssh.NewTunnelledSSHClient("core", tun, addr, getChecker(), false, timeout) } else { sshClient, err = ssh.NewSSHClient("core", addr, getChecker(), false, timeout) } if err != nil { return err } defer sshClient.Close() err = ssh.Shell(sshClient) return err }
func getRegistryClient() (client.API, error) { var dial func(string, string) (net.Conn, error) sshTimeout := time.Duration(Flags.SSHTimeout*1000) * time.Millisecond tun := getTunnelFlag() if tun != "" { sshClient, err := ssh.NewSSHClient("core", tun, getChecker(), false, sshTimeout) if err != nil { return nil, fmt.Errorf("failed initializing SSH client: %v", err) } dial = func(network, addr string) (net.Conn, error) { tcpaddr, err := net.ResolveTCPAddr(network, addr) if err != nil { return nil, err } return sshClient.DialTCP(network, nil, tcpaddr) } } tlsConfig, err := pkg.ReadTLSConfigFiles(Flags.EtcdCAFile, Flags.EtcdCertFile, Flags.EtcdKeyFile) if err != nil { return nil, err } trans := &http.Transport{ Dial: dial, TLSClientConfig: tlsConfig, } timeout := time.Duration(Flags.RequestTimeout*1000) * time.Millisecond machines := []string{Flags.Endpoint} eClient, err := etcd.NewClient(machines, trans, timeout) if err != nil { return nil, err } reg := registry.NewEtcdRegistry(eClient, Flags.EtcdKeyPrefix) // if msg, ok := checkVersion(reg); !ok { // stderr(msg) // } return &client.RegistryClient{Registry: reg}, nil }
func getHTTPClient() (client.API, error) { dialDomainSocket := strings.HasPrefix(globalFlags.Endpoint, "/") tunnelFunc := net.Dial tun := getTunnelFlag() if tun != "" { sshClient, err := ssh.NewSSHClient(globalFlags.SSHUserName, tun, getChecker(), false) if err != nil { return nil, fmt.Errorf("failed initializing SSH client: %v", err) } tunnelFunc = func(net, addr string) (net.Conn, error) { return sshClient.Dial(net, addr) } } dialFunc := tunnelFunc if dialDomainSocket { dialFunc = func(net, addr string) (net.Conn, error) { return tunnelFunc("unix", globalFlags.Endpoint) } } trans := pkg.LoggingHTTPTransport{ http.Transport{ Dial: dialFunc, }, } hc := http.Client{ Transport: &trans, } endpoint := globalFlags.Endpoint if dialDomainSocket { endpoint = "http://domain-sock/" } else if !strings.HasPrefix(endpoint, "http") { endpoint = fmt.Sprintf("http://%s", endpoint) } return client.NewHTTPClient(&hc, endpoint) }
func printUnitStatus(c *cli.Context, r *registry.Registry, jobName string) { js := r.GetJobState(jobName) if js == nil { fmt.Printf("%s does not appear to be running\n", jobName) syscall.Exit(1) } addr := fmt.Sprintf("%s:22", js.MachineState.PublicIP) var err error var sshClient *gossh.ClientConn if tun := getTunnelFlag(c); tun != "" { sshClient, err = ssh.NewTunnelledSSHClient("core", tun, addr) } else { sshClient, err = ssh.NewSSHClient("core", addr) } if err != nil { log.Fatalf("Unable to establish SSH connection: %v", err) } defer sshClient.Close() cmd := fmt.Sprintf("systemctl status -l %s", jobName) stdout, err := ssh.Execute(sshClient, cmd) if err != nil { log.Fatalf("Unable to execute command over SSH: %s", err.Error()) } for true { bytes, prefix, err := stdout.ReadLine() if err != nil { break } print(string(bytes)) if !prefix { print("\n") } } }
func getEtcdClient() (*etcdClient, error) { var dial func(string, string) (net.Conn, error) sshTimeout := time.Duration(fleet.Flags.SSHTimeout*1000) * time.Millisecond tun := getTunnelFlag() if tun != "" { sshClient, err := ssh.NewSSHClient("core", tun, getChecker(), false, sshTimeout) if err != nil { return nil, fmt.Errorf("failed initializing SSH client: %v", err) } dial = func(network, addr string) (net.Conn, error) { tcpaddr, err := net.ResolveTCPAddr(network, addr) if err != nil { return nil, err } return sshClient.DialTCP(network, nil, tcpaddr) } } tlsConfig, err := pkg.ReadTLSConfigFiles(fleet.Flags.EtcdCAFile, fleet.Flags.EtcdCertFile, fleet.Flags.EtcdKeyFile) if err != nil { return nil, err } trans := http.Transport{ Dial: dial, TLSClientConfig: tlsConfig, } timeout := time.Duration(fleet.Flags.RequestTimeout*1000) * time.Millisecond machines := []string{fleet.Flags.Endpoint} c := etcd.NewClient(machines) c.SetDialTimeout(timeout) // use custom transport with SSH tunnel capability c.SetTransport(&trans) return &etcdClient{etcd: c}, nil }
// runRemoteCommand runs the given command over SSH on the given IP, and returns // any error encountered and the exit status of the command func runRemoteCommand(cCmd *cobra.Command, addr string, cmd string, args ...string) (err error, exit int) { var sshClient *ssh.SSHForwardingClient timeout := getSSHTimeoutFlag(cCmd) if tun := getTunnelFlag(cCmd); tun != "" { sshClient, err = ssh.NewTunnelledSSHClient(globalFlags.SSHUserName, tun, addr, getChecker(cCmd), false, timeout) } else { sshClient, err = ssh.NewSSHClient(globalFlags.SSHUserName, addr, getChecker(cCmd), false, timeout) } if err != nil { return err, -1 } cmdargs := cmd for _, arg := range args { cmdargs += fmt.Sprintf(" %q", arg) } defer sshClient.Close() return ssh.Execute(sshClient, cmdargs) }
func runRemoteCommand(cmd string, ip string) (*ssh.Channel, error) { addr := fmt.Sprintf("%s:22", ip) var sshClient *ssh.SSHForwardingClient var err error if tun := getTunnelFlag(); tun != "" { sshClient, err = ssh.NewTunnelledSSHClient("core", tun, addr, getChecker(), false) } else { sshClient, err = ssh.NewSSHClient("core", addr, getChecker(), false) } if err != nil { return nil, err } defer sshClient.Close() channel, err := ssh.Execute(sshClient, cmd) if err != nil { return nil, err } return channel, nil }
func (c *FleetClient) sshConnect(name string) (*ssh.SSHForwardingClient, *machine.MachineState, error) { timeout := time.Duration(Flags.SSHTimeout*1000) * time.Millisecond ms, err := c.machineState(name) if err != nil { return nil, nil, err } // If name isn't a machine ID, try it as a unit instead if ms == nil { units, err := c.Units(name) if err != nil { return nil, nil, err } machID, err := c.findUnit(units[0]) if err != nil { return nil, nil, err } ms, err = c.machineState(machID) if err != nil || ms == nil { return nil, nil, err } } addr := ms.PublicIP if tun := getTunnelFlag(); tun != "" { sshClient, err := ssh.NewTunnelledSSHClient("core", tun, addr, getChecker(), false, timeout) return sshClient, ms, err } sshClient, err := ssh.NewSSHClient("core", addr, getChecker(), false, timeout) return sshClient, ms, err }
func getTunnelClient(driverEndpoint string, tunnelEndpoint string, maxRetries int) (client.API, error) { log.Printf("Using Fleet Tunnel connection for requests") getSSHClient := func() (interface{}, error) { return ssh.NewSSHClient("core", driverEndpoint, nil, false, defaultTimeout) } result, err := retry(getSSHClient, maxRetries) if err != nil { return nil, err } sshClient := result.(*ssh.SSHForwardingClient) dial := func(string, string) (net.Conn, error) { cmd := fmt.Sprintf("fleetctl fd-forward %s", tunnelEndpoint) return ssh.DialCommand(sshClient, cmd) } // This is needed to fake out the client - it isn't used // since we're overloading the dial method on the transport // but the client complains if it isn't set fakeHTTPEndpoint, err := url.Parse("http://domain-sock") if err != nil { return nil, err } trans := pkg.LoggingHTTPTransport{ Transport: http.Transport{ Dial: dial, }, } httpClient := http.Client{ Transport: &trans, } return client.NewHTTPClient(&httpClient, *fakeHTTPEndpoint) }
// getAPI returns an API to Fleet. func getAPI(hostAddr string, maxRetries int) (client.API, error) { if hostAddr == "" { return nullAPI{}, nil } getSSHClient := func() (interface{}, error) { return ssh.NewSSHClient("core", hostAddr, nil, false, time.Second*10) } result, err := retry(getSSHClient, maxRetries) if err != nil { return nil, err } sshClient := result.(*ssh.SSHForwardingClient) dial := func(string, string) (net.Conn, error) { cmd := "fleetctl fd-forward /var/run/fleet.sock" return ssh.DialCommand(sshClient, cmd) } trans := pkg.LoggingHTTPTransport{ Transport: http.Transport{ Dial: dial, }, } httpClient := http.Client{ Transport: &trans, } // since dial() ignores the endpoint, we just need something here that // won't make the HTTP client complain. endpoint, err := url.Parse("http://domain-sock") return client.NewHTTPClient(&httpClient, *endpoint) }
func getHTTPClient() (client.API, error) { ep, err := url.Parse(globalFlags.Endpoint) if err != nil { return nil, err } if len(ep.Scheme) == 0 { return nil, errors.New("URL scheme undefined") } tunnelFunc := net.Dial var tunneling bool tun := getTunnelFlag() if tun != "" { tunneling = true sshClient, err := ssh.NewSSHClient("core", tun, getChecker(), false, getSSHTimeoutFlag()) if err != nil { return nil, fmt.Errorf("failed initializing SSH client: %v", err) } tunnelFunc = func(net, addr string) (net.Conn, error) { return sshClient.Dial(net, addr) } } dialFunc := tunnelFunc if ep.Scheme == "unix" || ep.Scheme == "file" { if tunneling { return nil, errors.New("unable to dial unix socket through SSH tunnel") } // This commonly happens if the user misses the leading slash after the scheme. // For example, "unix://var/run/fleet.sock" would be parsed as host "var". if len(ep.Host) > 0 { return nil, fmt.Errorf("unable to connect to host %q with scheme %q", ep.Host, ep.Scheme) } // The Path field is only used for dialing and should not be used when // building any further HTTP requests. sockPath := ep.Path ep.Path = "" // http.Client does not natively support dialing a unix domain socket, so the // dial function must be overridden. dialFunc = func(net, addr string) (net.Conn, error) { return tunnelFunc("unix", sockPath) } // http.Client doesn't support the schemes "unix" or "file", but it // is safe to use "http" as dialFunc ignores it anyway. ep.Scheme = "http" // The Host field is not used for dialing, but will be exposed in debug logs. ep.Host = "domain-sock" } tlsConfig, err := pkg.ReadTLSConfigFiles(globalFlags.CAFile, globalFlags.CertFile, globalFlags.KeyFile) if err != nil { return nil, err } trans := pkg.LoggingHTTPTransport{ Transport: http.Transport{ Dial: dialFunc, TLSClientConfig: tlsConfig, }, } hc := http.Client{ Transport: &trans, } return client.NewHTTPClient(&hc, *ep) }
func getHTTPClient() (client.API, error) { endpoints := strings.Split(globalFlags.Endpoint, ",") if len(endpoints) > 1 { log.Warningf("multiple endpoints provided but only the first (%s) is used", endpoints[0]) } ep, err := url.Parse(endpoints[0]) if err != nil { return nil, err } if len(ep.Scheme) == 0 { return nil, errors.New("URL scheme undefined") } tun := getTunnelFlag() tunneling := tun != "" dialUnix := ep.Scheme == "unix" || ep.Scheme == "file" tunnelFunc := net.Dial if tunneling { sshClient, err := ssh.NewSSHClient(globalFlags.SSHUserName, tun, getChecker(), true, getSSHTimeoutFlag()) if err != nil { return nil, fmt.Errorf("failed initializing SSH client: %v", err) } if dialUnix { tgt := ep.Path tunnelFunc = func(string, string) (net.Conn, error) { log.Debugf("Establishing remote fleetctl proxy to %s", tgt) cmd := fmt.Sprintf(`fleetctl fd-forward %s`, tgt) return ssh.DialCommand(sshClient, cmd) } } else { tunnelFunc = sshClient.Dial } } dialFunc := tunnelFunc if dialUnix { // This commonly happens if the user misses the leading slash after the scheme. // For example, "unix://var/run/fleet.sock" would be parsed as host "var". if len(ep.Host) > 0 { return nil, fmt.Errorf("unable to connect to host %q with scheme %q", ep.Host, ep.Scheme) } // The Path field is only used for dialing and should not be used when // building any further HTTP requests. sockPath := ep.Path ep.Path = "" // If not tunneling to the unix socket, http.Client will dial it directly. // http.Client does not natively support dialing a unix domain socket, so the // dial function must be overridden. if !tunneling { dialFunc = func(string, string) (net.Conn, error) { return net.Dial("unix", sockPath) } } // http.Client doesn't support the schemes "unix" or "file", but it // is safe to use "http" as dialFunc ignores it anyway. ep.Scheme = "http" // The Host field is not used for dialing, but will be exposed in debug logs. ep.Host = "domain-sock" } tlsConfig, err := pkg.ReadTLSConfigFiles(globalFlags.CAFile, globalFlags.CertFile, globalFlags.KeyFile) if err != nil { return nil, err } trans := pkg.LoggingHTTPTransport{ Transport: http.Transport{ Dial: dialFunc, TLSClientConfig: tlsConfig, }, } hc := http.Client{ Transport: &trans, } return client.NewHTTPClient(&hc, *ep) }
func sshAction(c *cli.Context) { r := getRegistry(c) args := c.Args() unit := c.String("unit") if len(args) == 0 && unit == "" { log.Fatalf("Provide one machine or unit") } var addr string if unit == "" { lookup := args[0] args = args[1:] states := r.GetActiveMachines() var match *machine.MachineState for i, _ := range states { machState := states[i] if !strings.HasPrefix(machState.BootId, lookup) { continue } else if match != nil { log.Fatalf("Found more than one Machine, be more specfic") } match = &machState } if match == nil { log.Fatalf("Could not find provided Machine") } addr = fmt.Sprintf("%s:22", match.PublicIP) } else { js := r.GetJobState(unit) if js == nil { log.Fatalf("Requested unit %s does not appear to be running", unit) } addr = fmt.Sprintf("%s:22", js.MachineState.PublicIP) } var err error var sshClient *gossh.ClientConn if tun := getTunnelFlag(c); tun != "" { sshClient, err = ssh.NewTunnelledSSHClient("core", tun, addr) } else { sshClient, err = ssh.NewSSHClient("core", addr) } if err != nil { log.Fatalf("Unable to establish SSH connection: %v", err) return } defer sshClient.Close() if len(args) > 0 { cmd := strings.Join(args, " ") stdout, err := ssh.Execute(sshClient, cmd) if err != nil { log.Fatalf("Unable to run command over SSH: %s", err.Error()) } for { bytes, prefix, err := stdout.ReadLine() if err != nil { break } print(string(bytes)) if !prefix { print("\n") } } } else { if err := ssh.Shell(sshClient); err != nil { log.Fatalf(err.Error()) } } }
func runSSH(args []string) (exit int) { if flagUnit != "" && flagMachine != "" { stderr("Both machine and unit flags provided, please specify only one.") return 1 } var err error var addr string switch { case flagMachine != "": addr, _, err = findAddressInMachineList(flagMachine) case flagUnit != "": addr, _, err = findAddressInRunningUnits(flagUnit) default: addr, err = globalMachineLookup(args) // trim machine/unit name from args if len(args) > 0 { args = args[1:] } } if err != nil { stderr("Unable to proceed: %v", err) return 1 } if addr == "" { stderr("Could not determine address of machine.") return 1 } args = pkg.TrimToDashes(args) var sshClient *ssh.SSHForwardingClient timeout := getSSHTimeoutFlag() if tun := getTunnelFlag(); tun != "" { sshClient, err = ssh.NewTunnelledSSHClient(globalFlags.SSHUserName, tun, addr, getChecker(), flagSSHAgentForwarding, timeout) } else { sshClient, err = ssh.NewSSHClient(globalFlags.SSHUserName, addr, getChecker(), flagSSHAgentForwarding, timeout) } if err != nil { stderr("Failed building SSH client: %v", err) return 1 } defer sshClient.Close() if len(args) > 0 { cmd := strings.Join(args, " ") err, exit = ssh.Execute(sshClient, cmd) if err != nil { stderr("Failed running command over SSH: %v", err) } } else { if err := ssh.Shell(sshClient); err != nil { stderr("Failed opening shell over SSH: %v", err) exit = 1 } } return }
func sshAction(c *cli.Context) { unit := c.String("unit") machine := c.String("machine") if unit != "" && machine != "" { log.Fatal("Both flags, machine and unit provided, please specify only one") } args := c.Args() var err error var addr string switch { case machine != "": addr, _ = findAddressInMachineList(machine) case unit != "": addr, _ = findAddressInRunningUnits(unit) default: addr, err = globalMachineLookup(args) args = args[1:] } if err != nil { log.Fatal(err) } if addr == "" { log.Fatalf("Requested machine could not be found") } var sshClient *gossh.ClientConn if tun := getTunnelFlag(); tun != "" { sshClient, err = ssh.NewTunnelledSSHClient("core", tun, addr) } else { sshClient, err = ssh.NewSSHClient("core", addr) } if err != nil { log.Fatal(err.Error()) return } defer sshClient.Close() if len(args) > 0 { cmd := strings.Join(args, " ") stdout, err := ssh.Execute(sshClient, cmd) if err != nil { log.Fatalf("Unable to run command over SSH: %s", err.Error()) } for { bytes, prefix, err := stdout.ReadLine() if err != nil { break } fmt.Print(string(bytes)) if !prefix { fmt.Print("\n") } } } else { if err := ssh.Shell(sshClient); err != nil { log.Fatalf(err.Error()) } } }