github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/apiserver/sshclient/facade.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  // Package sshclient implements the API endpoint required for Juju
     5  // clients that wish to make SSH connections to Juju managed machines.
     6  package sshclient
     7  
     8  import (
     9  	"github.com/juju/errors"
    10  
    11  	"github.com/juju/juju/apiserver/common"
    12  	"github.com/juju/juju/apiserver/facade"
    13  	"github.com/juju/juju/apiserver/params"
    14  	"github.com/juju/juju/network"
    15  	"github.com/juju/juju/permission"
    16  )
    17  
    18  func init() {
    19  	common.RegisterStandardFacade("SSHClient", 1, newFacade)
    20  }
    21  
    22  // Facade implements the API required by the sshclient worker.
    23  type Facade struct {
    24  	backend    Backend
    25  	authorizer facade.Authorizer
    26  }
    27  
    28  // New returns a new API facade for the sshclient worker.
    29  func New(backend Backend, _ facade.Resources, authorizer facade.Authorizer) (*Facade, error) {
    30  	if !authorizer.AuthClient() {
    31  		return nil, common.ErrPerm
    32  	}
    33  	return &Facade{backend: backend, authorizer: authorizer}, nil
    34  }
    35  
    36  func (facade *Facade) checkIsModelAdmin() error {
    37  	isModelAdmin, err := facade.authorizer.HasPermission(permission.AdminAccess, facade.backend.ModelTag())
    38  	if err != nil {
    39  		return errors.Trace(err)
    40  	}
    41  	if !isModelAdmin {
    42  		return common.ErrPerm
    43  	}
    44  	return nil
    45  }
    46  
    47  // PublicAddress reports the preferred public network address for one
    48  // or more entities. Machines and units are suppored.
    49  func (facade *Facade) PublicAddress(args params.Entities) (params.SSHAddressResults, error) {
    50  	if err := facade.checkIsModelAdmin(); err != nil {
    51  		return params.SSHAddressResults{}, errors.Trace(err)
    52  	}
    53  
    54  	getter := func(m SSHMachine) (network.Address, error) { return m.PublicAddress() }
    55  	return facade.getAddresses(args, getter)
    56  }
    57  
    58  // PrivateAddress reports the preferred private network address for one or
    59  // more entities. Machines and units are supported.
    60  func (facade *Facade) PrivateAddress(args params.Entities) (params.SSHAddressResults, error) {
    61  	if err := facade.checkIsModelAdmin(); err != nil {
    62  		return params.SSHAddressResults{}, errors.Trace(err)
    63  	}
    64  
    65  	getter := func(m SSHMachine) (network.Address, error) { return m.PrivateAddress() }
    66  	return facade.getAddresses(args, getter)
    67  }
    68  
    69  func (facade *Facade) getAddresses(args params.Entities, getter func(SSHMachine) (network.Address, error)) (
    70  	params.SSHAddressResults, error,
    71  ) {
    72  	out := params.SSHAddressResults{
    73  		Results: make([]params.SSHAddressResult, len(args.Entities)),
    74  	}
    75  	for i, entity := range args.Entities {
    76  		machine, err := facade.backend.GetMachineForEntity(entity.Tag)
    77  		if err != nil {
    78  			out.Results[i].Error = common.ServerError(err)
    79  		} else {
    80  			address, err := getter(machine)
    81  			if err != nil {
    82  				out.Results[i].Error = common.ServerError(err)
    83  			} else {
    84  				out.Results[i].Address = address.Value
    85  			}
    86  		}
    87  	}
    88  	return out, nil
    89  }
    90  
    91  // PublicKeys returns the public SSH hosts for one or more
    92  // entities. Machines and units are supported.
    93  func (facade *Facade) PublicKeys(args params.Entities) (params.SSHPublicKeysResults, error) {
    94  	if err := facade.checkIsModelAdmin(); err != nil {
    95  		return params.SSHPublicKeysResults{}, errors.Trace(err)
    96  	}
    97  
    98  	out := params.SSHPublicKeysResults{
    99  		Results: make([]params.SSHPublicKeysResult, len(args.Entities)),
   100  	}
   101  	for i, entity := range args.Entities {
   102  		machine, err := facade.backend.GetMachineForEntity(entity.Tag)
   103  		if err != nil {
   104  			out.Results[i].Error = common.ServerError(err)
   105  		} else {
   106  			keys, err := facade.backend.GetSSHHostKeys(machine.MachineTag())
   107  			if err != nil {
   108  				out.Results[i].Error = common.ServerError(err)
   109  			} else {
   110  				out.Results[i].PublicKeys = []string(keys)
   111  			}
   112  		}
   113  	}
   114  	return out, nil
   115  }
   116  
   117  // Proxy returns whether SSH connections should be proxied through the
   118  // controller hosts for the model associated with the API connection.
   119  func (facade *Facade) Proxy() (params.SSHProxyResult, error) {
   120  	if err := facade.checkIsModelAdmin(); err != nil {
   121  		return params.SSHProxyResult{}, errors.Trace(err)
   122  	}
   123  	config, err := facade.backend.ModelConfig()
   124  	if err != nil {
   125  		return params.SSHProxyResult{}, err
   126  	}
   127  	return params.SSHProxyResult{UseProxy: config.ProxySSH()}, nil
   128  }