github.com/mwhudson/juju@v0.0.0-20160512215208-90ff01f3497f/api/sshclient/facade.go (about) 1 // Copyright 2016 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package sshclient 5 6 import ( 7 "github.com/juju/errors" 8 "github.com/juju/names" 9 10 "github.com/juju/juju/api/base" 11 "github.com/juju/juju/apiserver/params" 12 ) 13 14 // NewFacade returns a new Facade based on an existing API connection. 15 func NewFacade(caller base.APICaller) *Facade { 16 return &Facade{base.NewFacadeCaller(caller, "SSHClient")} 17 } 18 19 type Facade struct { 20 caller base.FacadeCaller 21 } 22 23 // PublicAddress returns the public address for the SSH target 24 // provided. The target may be provided as a machine ID or unit name. 25 func (facade *Facade) PublicAddress(target string) (string, error) { 26 addr, err := facade.addressCall("PublicAddress", target) 27 return addr, errors.Trace(err) 28 } 29 30 // PrivateAddress returns the private address for the SSH target 31 // provided. The target may be provided as a machine ID or unit name. 32 func (facade *Facade) PrivateAddress(target string) (string, error) { 33 addr, err := facade.addressCall("PrivateAddress", target) 34 return addr, errors.Trace(err) 35 } 36 37 func (facade *Facade) addressCall(callName, target string) (string, error) { 38 entities, err := targetToEntities(target) 39 if err != nil { 40 return "", errors.Trace(err) 41 } 42 var out params.SSHAddressResults 43 err = facade.caller.FacadeCall(callName, entities, &out) 44 if err != nil { 45 return "", errors.Trace(err) 46 } 47 if len(out.Results) != 1 { 48 return "", countError(len(out.Results)) 49 } 50 if err := out.Results[0].Error; err != nil { 51 return "", errors.Trace(err) 52 } 53 return out.Results[0].Address, nil 54 } 55 56 // PublicKeys returns the SSH public host keys for the SSH target 57 // provided. The target may be provided as a machine ID or unit name. 58 func (facade *Facade) PublicKeys(target string) ([]string, error) { 59 entities, err := targetToEntities(target) 60 if err != nil { 61 return nil, errors.Trace(err) 62 } 63 var out params.SSHPublicKeysResults 64 err = facade.caller.FacadeCall("PublicKeys", entities, &out) 65 if err != nil { 66 return nil, errors.Trace(err) 67 } 68 if len(out.Results) != 1 { 69 return nil, countError(len(out.Results)) 70 } 71 if err := out.Results[0].Error; err != nil { 72 return nil, errors.Trace(err) 73 } 74 return out.Results[0].PublicKeys, nil 75 } 76 77 // Proxy returns whether SSH connections should be proxied through the 78 // controller hosts for the associated model. 79 func (facade *Facade) Proxy() (bool, error) { 80 var out params.SSHProxyResult 81 err := facade.caller.FacadeCall("Proxy", nil, &out) 82 if err != nil { 83 return false, errors.Trace(err) 84 } 85 return out.UseProxy, nil 86 } 87 88 func targetToEntities(target string) (params.Entities, error) { 89 tag, err := targetToTag(target) 90 if err != nil { 91 return params.Entities{}, errors.Trace(err) 92 } 93 return params.Entities{ 94 Entities: []params.Entity{{Tag: tag.String()}}, 95 }, nil 96 } 97 98 func targetToTag(target string) (names.Tag, error) { 99 switch { 100 case names.IsValidMachine(target): 101 return names.NewMachineTag(target), nil 102 case names.IsValidUnit(target): 103 return names.NewUnitTag(target), nil 104 default: 105 return nil, errors.NotValidf("target %q", target) 106 } 107 } 108 109 // countError complains about malformed results. 110 func countError(count int) error { 111 return errors.Errorf("expected 1 result, got %d", count) 112 }