github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/apiserver/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  	"github.com/juju/loggo"
     9  	"github.com/juju/names"
    10  
    11  	"github.com/juju/juju/apiserver/common"
    12  	"github.com/juju/juju/apiserver/params"
    13  	"github.com/juju/juju/state"
    14  )
    15  
    16  var logger = loggo.GetLogger("juju.apiserver.spaces")
    17  
    18  func init() {
    19  	common.RegisterStandardFacade("Spaces", 1, NewAPI)
    20  }
    21  
    22  // API defines the methods the Spaces API facade implements.
    23  type API interface {
    24  	CreateSpaces(params.CreateSpacesParams) (params.ErrorResults, error)
    25  	ListSpaces() (params.ListSpacesResults, error)
    26  }
    27  
    28  // Backing defines the state methods this facede needs, so they can be
    29  // mocked for testing.
    30  type Backing interface {
    31  	// AddSpace creates a space
    32  	AddSpace(name string, subnetIds []string, public bool) error
    33  
    34  	// AllSpaces returns all known Juju network spaces.
    35  	AllSpaces() ([]common.BackingSpace, error)
    36  }
    37  
    38  // spacesAPI implements the API interface.
    39  type spacesAPI struct {
    40  	backing    Backing
    41  	resources  *common.Resources
    42  	authorizer common.Authorizer
    43  }
    44  
    45  // NewAPI creates a new Space API server-side facade with a
    46  // state.State backing.
    47  func NewAPI(st *state.State, res *common.Resources, auth common.Authorizer) (API, error) {
    48  	return newAPIWithBacking(&stateShim{st: st}, res, auth)
    49  }
    50  
    51  // newAPIWithBacking creates a new server-side Spaces API facade with
    52  // the given Backing.
    53  func newAPIWithBacking(backing Backing, resources *common.Resources, authorizer common.Authorizer) (API, error) {
    54  	// Only clients can access the Spaces facade.
    55  	if !authorizer.AuthClient() {
    56  		return nil, common.ErrPerm
    57  	}
    58  	return &spacesAPI{
    59  		backing:    backing,
    60  		resources:  resources,
    61  		authorizer: authorizer,
    62  	}, nil
    63  }
    64  
    65  // CreateSpaces creates a new Juju network space, associating the
    66  // specified subnets with it (optional; can be empty).
    67  func (api *spacesAPI) CreateSpaces(args params.CreateSpacesParams) (params.ErrorResults, error) {
    68  	results := params.ErrorResults{
    69  		Results: make([]params.ErrorResult, len(args.Spaces)),
    70  	}
    71  
    72  	for i, space := range args.Spaces {
    73  		err := api.createOneSpace(space)
    74  		if err == nil {
    75  			continue
    76  		}
    77  		results.Results[i].Error = common.ServerError(errors.Trace(err))
    78  	}
    79  
    80  	return results, nil
    81  }
    82  
    83  func (api *spacesAPI) createOneSpace(args params.CreateSpaceParams) error {
    84  	// Validate the args, assemble information for api.backing.AddSpaces
    85  	var subnets []string
    86  
    87  	spaceTag, err := names.ParseSpaceTag(args.SpaceTag)
    88  	if err != nil {
    89  		return errors.Trace(err)
    90  	}
    91  
    92  	for _, tag := range args.SubnetTags {
    93  		subnetTag, err := names.ParseSubnetTag(tag)
    94  		if err != nil {
    95  			return errors.Trace(err)
    96  		}
    97  		subnets = append(subnets, subnetTag.Id())
    98  	}
    99  
   100  	// Add the validated space
   101  	err = api.backing.AddSpace(spaceTag.Id(), subnets, args.Public)
   102  	if err != nil {
   103  		return errors.Trace(err)
   104  	}
   105  	return nil
   106  }
   107  
   108  func backingSubnetToParamsSubnet(subnet common.BackingSubnet) params.Subnet {
   109  	cidr := subnet.CIDR()
   110  	vlantag := subnet.VLANTag()
   111  	providerid := subnet.ProviderId()
   112  	zones := subnet.AvailabilityZones()
   113  	status := subnet.Status()
   114  	var spaceTag names.SpaceTag
   115  	if subnet.SpaceName() != "" {
   116  		spaceTag = names.NewSpaceTag(subnet.SpaceName())
   117  	}
   118  
   119  	return params.Subnet{
   120  		CIDR:       cidr,
   121  		VLANTag:    vlantag,
   122  		ProviderId: providerid,
   123  		Zones:      zones,
   124  		Status:     status,
   125  		SpaceTag:   spaceTag.String(),
   126  		Life:       subnet.Life(),
   127  	}
   128  }
   129  
   130  // ListSpaces lists all the available spaces and their associated subnets.
   131  func (api *spacesAPI) ListSpaces() (results params.ListSpacesResults, err error) {
   132  	spaces, err := api.backing.AllSpaces()
   133  	if err != nil {
   134  		return results, errors.Trace(err)
   135  	}
   136  
   137  	results.Results = make([]params.Space, len(spaces))
   138  	for i, space := range spaces {
   139  		result := params.Space{}
   140  		result.Name = space.Name()
   141  
   142  		subnets, err := space.Subnets()
   143  		if err != nil {
   144  			err = errors.Annotatef(err, "fetching subnets")
   145  			result.Error = common.ServerError(err)
   146  			results.Results[i] = result
   147  			continue
   148  		}
   149  
   150  		result.Subnets = make([]params.Subnet, len(subnets))
   151  		for i, subnet := range subnets {
   152  			result.Subnets[i] = backingSubnetToParamsSubnet(subnet)
   153  		}
   154  		results.Results[i] = result
   155  	}
   156  	return results, nil
   157  }