// GetSSHAddr returns the username and the hostname of the remove machine to ssh. // // It assume user exists on the remove machine with the same Koding username. // It may also return a custom port number, if other than a default should // be used. func (s *SSHKey) GetSSHAddr(name string) (userhost, port string, err error) { infos, err := s.Klient.RemoteList() if err != nil { return "", "", err } info, ok := infos.FindFromName(name) if !ok { s.Log.Error("No machine found with specified name: `%s`", name) return "", "", ErrMachineNotFound } remoteUsername, err := s.GetUsername(name) if err != nil { return "", "", err } endpoints, err := s.Discover.Discover(info.IP, "ssh") if err != nil { return fmt.Sprintf("%s@%s", remoteUsername, info.IP), "", nil } addr := endpoints[0].Addr // We prefer local routes to use first, if there's none, we use first // discovered route. if e := endpoints.Filter(discover.ByLocal(true)); len(e) != 0 { // All local routes will do, typically there's only one, // we use the first one and ignore the rest. addr = e[0].Addr } host, port, err := net.SplitHostPort(addr) if err != nil { host = addr } return fmt.Sprintf("%s@%s", remoteUsername, host), port, nil }
// Create updates internal state of machine group. It gets the current // information about user machines so it can add new ones to group. func (g *Group) SSH(req *SSHRequest) (*SSHResponse, error) { if req == nil { return nil, errors.New("invalid nil request") } c, err := g.client.Client(req.ID) if err != nil { return nil, err } // Use provided username or ask remote machine to return it. username := req.Username if username == "" { if username, err = c.CurrentUser(); err != nil { return nil, err } } // Add pubic key to remote machine authorized keys. if req.PublicKey != "" { if err := c.SSHAddKeys(username, req.PublicKey); err != nil { return nil, err } } // Check for tunneled connections. addr, err := g.address.Latest(req.ID, "tunnel") if err != nil { // There are no tunnel addresses. Get latest IP. if addr, err = g.address.Latest(req.ID, "ip"); err != nil { return nil, err } return &SSHResponse{ Username: username, Host: addr.Value, }, nil } // Discover tunnel SSH address. endpoints, err := g.discover.Discover(addr.Value, "ssh") if err != nil { return &SSHResponse{ Username: username, Host: addr.Value, }, nil } tuneladdr := endpoints[0].Addr // We prefer local routes to use first, if there's none, we use first // discovered route. if e := endpoints.Filter(discover.ByLocal(true)); len(e) != 0 { // All local routes will do, typically there's only one, // we use the first one and ignore the rest. tuneladdr = e[0].Addr } host, port, err := net.SplitHostPort(tuneladdr) if err != nil { host, port = tuneladdr, "0" } n, err := strconv.Atoi(port) if err != nil { return nil, err } return &SSHResponse{ Username: username, Host: host, Port: n, }, nil }