github.com/niedbalski/juju@v0.0.0-20190215020005-8ff100488e47/apiserver/facades/client/spaces/spaces.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package spaces
     5  
     6  import (
     7  	"github.com/juju/errors"
     8  
     9  	"github.com/juju/juju/apiserver/common"
    10  	"github.com/juju/juju/apiserver/common/networkingcommon"
    11  	"github.com/juju/juju/apiserver/facade"
    12  	"github.com/juju/juju/apiserver/params"
    13  	"github.com/juju/juju/environs"
    14  	"github.com/juju/juju/environs/context"
    15  	"github.com/juju/juju/permission"
    16  	"github.com/juju/juju/state"
    17  )
    18  
    19  // API defines the methods the Spaces API facade implements.
    20  type API interface {
    21  	CreateSpaces(params.CreateSpacesParams) (params.ErrorResults, error)
    22  	ListSpaces() (params.ListSpacesResults, error)
    23  	ReloadSpaces() error
    24  }
    25  
    26  // APIV2 is missing ReloadSpaces method
    27  type APIV2 interface {
    28  	CreateSpaces(params.CreateSpacesParams) (params.ErrorResults, error)
    29  	ListSpaces() (params.ListSpacesResults, error)
    30  }
    31  
    32  // spacesAPI implements the API interface.
    33  type spacesAPI struct {
    34  	backing    networkingcommon.NetworkBacking
    35  	resources  facade.Resources
    36  	authorizer facade.Authorizer
    37  	context    context.ProviderCallContext
    38  }
    39  
    40  // NewAPI creates a new Space API server-side facade with a
    41  // state.State backing.
    42  func NewAPI(st *state.State, res facade.Resources, auth facade.Authorizer) (API, error) {
    43  	stateShim, err := networkingcommon.NewStateShim(st)
    44  	if err != nil {
    45  		return nil, errors.Trace(err)
    46  	}
    47  	return newAPIWithBacking(stateShim, state.CallContext(st), res, auth)
    48  }
    49  
    50  // newAPIWithBacking creates a new server-side Spaces API facade with
    51  // the given Backing.
    52  func newAPIWithBacking(backing networkingcommon.NetworkBacking, ctx context.ProviderCallContext, resources facade.Resources, authorizer facade.Authorizer) (API, error) {
    53  	// Only clients can access the Spaces facade.
    54  	if !authorizer.AuthClient() {
    55  		return nil, common.ErrPerm
    56  	}
    57  	return &spacesAPI{
    58  		backing:    backing,
    59  		resources:  resources,
    60  		authorizer: authorizer,
    61  		context:    ctx,
    62  	}, nil
    63  }
    64  
    65  // NewAPIV2 is a wrapper that creates a V2 spaces API.
    66  func NewAPIV2(st *state.State, res facade.Resources, auth facade.Authorizer) (APIV2, error) {
    67  	return NewAPI(st, res, auth)
    68  }
    69  
    70  // CreateSpaces creates a new Juju network space, associating the
    71  // specified subnets with it (optional; can be empty).
    72  func (api *spacesAPI) CreateSpaces(args params.CreateSpacesParams) (results params.ErrorResults, err error) {
    73  	isAdmin, err := api.authorizer.HasPermission(permission.AdminAccess, api.backing.ModelTag())
    74  	if err != nil && !errors.IsNotFound(err) {
    75  		return results, errors.Trace(err)
    76  	}
    77  	if !isAdmin {
    78  		return results, common.ServerError(common.ErrPerm)
    79  	}
    80  
    81  	return networkingcommon.CreateSpaces(api.backing, api.context, args)
    82  }
    83  
    84  // ListSpaces lists all the available spaces and their associated subnets.
    85  func (api *spacesAPI) ListSpaces() (results params.ListSpacesResults, err error) {
    86  	canRead, err := api.authorizer.HasPermission(permission.ReadAccess, api.backing.ModelTag())
    87  	if err != nil && !errors.IsNotFound(err) {
    88  		return results, errors.Trace(err)
    89  	}
    90  	if !canRead {
    91  		return results, common.ServerError(common.ErrPerm)
    92  	}
    93  
    94  	err = networkingcommon.SupportsSpaces(api.backing, api.context)
    95  	if err != nil {
    96  		return results, common.ServerError(errors.Trace(err))
    97  	}
    98  
    99  	spaces, err := api.backing.AllSpaces()
   100  	if err != nil {
   101  		return results, errors.Trace(err)
   102  	}
   103  
   104  	results.Results = make([]params.Space, len(spaces))
   105  	for i, space := range spaces {
   106  		result := params.Space{}
   107  		result.Name = space.Name()
   108  
   109  		subnets, err := space.Subnets()
   110  		if err != nil {
   111  			err = errors.Annotatef(err, "fetching subnets")
   112  			result.Error = common.ServerError(err)
   113  			results.Results[i] = result
   114  			continue
   115  		}
   116  
   117  		result.Subnets = make([]params.Subnet, len(subnets))
   118  		for i, subnet := range subnets {
   119  			result.Subnets[i] = networkingcommon.BackingSubnetToParamsSubnet(subnet)
   120  		}
   121  		results.Results[i] = result
   122  	}
   123  	return results, nil
   124  }
   125  
   126  // RefreshSpaces refreshes spaces from substrate
   127  func (api *spacesAPI) ReloadSpaces() error {
   128  	canWrite, err := api.authorizer.HasPermission(permission.WriteAccess, api.backing.ModelTag())
   129  	if err != nil && !errors.IsNotFound(err) {
   130  		return errors.Trace(err)
   131  	}
   132  	if !canWrite {
   133  		return common.ServerError(common.ErrPerm)
   134  	}
   135  	env, err := environs.GetEnviron(api.backing, environs.New)
   136  	if err != nil {
   137  		return errors.Trace(err)
   138  	}
   139  	return errors.Trace(api.backing.ReloadSpaces(env))
   140  }