github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/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 "gopkg.in/juju/names.v2" 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(callCloser base.APICallCloser) *Facade { 16 clientFacade, caller := base.NewClientFacade(callCloser, "SSHClient") 17 return &Facade{ 18 ClientFacade: clientFacade, 19 caller: caller, 20 } 21 } 22 23 type Facade struct { 24 base.ClientFacade 25 caller base.FacadeCaller 26 } 27 28 // PublicAddress returns the public address for the SSH target 29 // provided. The target may be provided as a machine ID or unit name. 30 func (facade *Facade) PublicAddress(target string) (string, error) { 31 addr, err := facade.addressCall("PublicAddress", target) 32 return addr, errors.Trace(err) 33 } 34 35 // PrivateAddress returns the private address for the SSH target 36 // provided. The target may be provided as a machine ID or unit name. 37 func (facade *Facade) PrivateAddress(target string) (string, error) { 38 addr, err := facade.addressCall("PrivateAddress", target) 39 return addr, errors.Trace(err) 40 } 41 42 func (facade *Facade) addressCall(callName, target string) (string, error) { 43 entities, err := targetToEntities(target) 44 if err != nil { 45 return "", errors.Trace(err) 46 } 47 var out params.SSHAddressResults 48 err = facade.caller.FacadeCall(callName, entities, &out) 49 if err != nil { 50 return "", errors.Trace(err) 51 } 52 if len(out.Results) != 1 { 53 return "", countError(len(out.Results)) 54 } 55 if err := out.Results[0].Error; err != nil { 56 return "", errors.Trace(err) 57 } 58 return out.Results[0].Address, nil 59 } 60 61 // PublicKeys returns the SSH public host keys for the SSH target 62 // provided. The target may be provided as a machine ID or unit name. 63 func (facade *Facade) PublicKeys(target string) ([]string, error) { 64 entities, err := targetToEntities(target) 65 if err != nil { 66 return nil, errors.Trace(err) 67 } 68 var out params.SSHPublicKeysResults 69 err = facade.caller.FacadeCall("PublicKeys", entities, &out) 70 if err != nil { 71 return nil, errors.Trace(err) 72 } 73 if len(out.Results) != 1 { 74 return nil, countError(len(out.Results)) 75 } 76 if err := out.Results[0].Error; err != nil { 77 return nil, errors.Trace(err) 78 } 79 return out.Results[0].PublicKeys, nil 80 } 81 82 // Proxy returns whether SSH connections should be proxied through the 83 // controller hosts for the associated model. 84 func (facade *Facade) Proxy() (bool, error) { 85 var out params.SSHProxyResult 86 err := facade.caller.FacadeCall("Proxy", nil, &out) 87 if err != nil { 88 return false, errors.Trace(err) 89 } 90 return out.UseProxy, nil 91 } 92 93 func targetToEntities(target string) (params.Entities, error) { 94 tag, err := targetToTag(target) 95 if err != nil { 96 return params.Entities{}, errors.Trace(err) 97 } 98 return params.Entities{ 99 Entities: []params.Entity{{Tag: tag.String()}}, 100 }, nil 101 } 102 103 func targetToTag(target string) (names.Tag, error) { 104 switch { 105 case names.IsValidMachine(target): 106 return names.NewMachineTag(target), nil 107 case names.IsValidUnit(target): 108 return names.NewUnitTag(target), nil 109 default: 110 return nil, errors.NotValidf("target %q", target) 111 } 112 } 113 114 // countError complains about malformed results. 115 func countError(count int) error { 116 return errors.Errorf("expected 1 result, got %d", count) 117 }