github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/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 // AllAddresses returns all addresses for the SSH target provided. The target 43 // may be provided as a machine ID or unit name. 44 func (facade *Facade) AllAddresses(target string) ([]string, error) { 45 entities, err := targetToEntities(target) 46 if err != nil { 47 return nil, errors.Trace(err) 48 } 49 var out params.SSHAddressesResults 50 err = facade.caller.FacadeCall("AllAddresses", entities, &out) 51 if err != nil { 52 return nil, errors.Trace(err) 53 } 54 if len(out.Results) != 1 { 55 return nil, countError(len(out.Results)) 56 } 57 if err := out.Results[0].Error; err != nil { 58 return nil, errors.Trace(err) 59 } 60 return out.Results[0].Addresses, nil 61 } 62 63 func (facade *Facade) addressCall(callName, target string) (string, error) { 64 entities, err := targetToEntities(target) 65 if err != nil { 66 return "", errors.Trace(err) 67 } 68 var out params.SSHAddressResults 69 err = facade.caller.FacadeCall(callName, entities, &out) 70 if err != nil { 71 return "", errors.Trace(err) 72 } 73 if len(out.Results) != 1 { 74 return "", countError(len(out.Results)) 75 } 76 if err := out.Results[0].Error; err != nil { 77 return "", errors.Trace(err) 78 } 79 return out.Results[0].Address, nil 80 } 81 82 // PublicKeys returns the SSH public host keys for the SSH target 83 // provided. The target may be provided as a machine ID or unit name. 84 func (facade *Facade) PublicKeys(target string) ([]string, error) { 85 entities, err := targetToEntities(target) 86 if err != nil { 87 return nil, errors.Trace(err) 88 } 89 var out params.SSHPublicKeysResults 90 err = facade.caller.FacadeCall("PublicKeys", entities, &out) 91 if err != nil { 92 return nil, errors.Trace(err) 93 } 94 if len(out.Results) != 1 { 95 return nil, countError(len(out.Results)) 96 } 97 if err := out.Results[0].Error; err != nil { 98 return nil, errors.Trace(err) 99 } 100 return out.Results[0].PublicKeys, nil 101 } 102 103 // Proxy returns whether SSH connections should be proxied through the 104 // controller hosts for the associated model. 105 func (facade *Facade) Proxy() (bool, error) { 106 var out params.SSHProxyResult 107 err := facade.caller.FacadeCall("Proxy", nil, &out) 108 if err != nil { 109 return false, errors.Trace(err) 110 } 111 return out.UseProxy, nil 112 } 113 114 func targetToEntities(target string) (params.Entities, error) { 115 tag, err := targetToTag(target) 116 if err != nil { 117 return params.Entities{}, errors.Trace(err) 118 } 119 return params.Entities{ 120 Entities: []params.Entity{{Tag: tag.String()}}, 121 }, nil 122 } 123 124 func targetToTag(target string) (names.Tag, error) { 125 switch { 126 case names.IsValidMachine(target): 127 return names.NewMachineTag(target), nil 128 case names.IsValidUnit(target): 129 return names.NewUnitTag(target), nil 130 default: 131 return nil, errors.NotValidf("target %q", target) 132 } 133 } 134 135 // countError complains about malformed results. 136 func countError(count int) error { 137 return errors.Errorf("expected 1 result, got %d", count) 138 }