github.com/makyo/juju@v0.0.0-20160425123129-2608902037e9/component/all/payload.go (about)

     1  // Copyright 2015 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package all
     5  
     6  import (
     7  	"reflect"
     8  
     9  	"github.com/juju/cmd"
    10  	"github.com/juju/errors"
    11  
    12  	"github.com/juju/juju/api"
    13  	"github.com/juju/juju/api/base"
    14  	"github.com/juju/juju/apiserver/common"
    15  	"github.com/juju/juju/cmd/juju/commands"
    16  	"github.com/juju/juju/cmd/modelcmd"
    17  	"github.com/juju/juju/payload"
    18  	"github.com/juju/juju/payload/api/client"
    19  	internalclient "github.com/juju/juju/payload/api/private/client"
    20  	internalserver "github.com/juju/juju/payload/api/private/server"
    21  	"github.com/juju/juju/payload/api/server"
    22  	"github.com/juju/juju/payload/context"
    23  	"github.com/juju/juju/payload/persistence"
    24  	payloadstate "github.com/juju/juju/payload/state"
    25  	"github.com/juju/juju/payload/status"
    26  	"github.com/juju/juju/state"
    27  	unitercontext "github.com/juju/juju/worker/uniter/runner/context"
    28  	"github.com/juju/juju/worker/uniter/runner/jujuc"
    29  )
    30  
    31  const payloadsHookContextFacade = payload.ComponentName + "-hook-context"
    32  
    33  type payloads struct{}
    34  
    35  func (c payloads) registerForServer() error {
    36  	c.registerState()
    37  	c.registerPublicFacade()
    38  
    39  	c.registerHookContext()
    40  
    41  	return nil
    42  }
    43  
    44  func (c payloads) registerForClient() error {
    45  	c.registerPublicCommands()
    46  	return nil
    47  }
    48  
    49  func (payloads) newPublicFacade(st *state.State, resources *common.Resources, authorizer common.Authorizer) (*server.PublicAPI, error) {
    50  	up, err := st.EnvPayloads()
    51  	if err != nil {
    52  		return nil, errors.Trace(err)
    53  	}
    54  	return server.NewPublicAPI(up), nil
    55  }
    56  
    57  func (c payloads) registerPublicFacade() {
    58  	if !markRegistered(payload.ComponentName, "public-facade") {
    59  		return
    60  	}
    61  
    62  	const version = 1
    63  	common.RegisterStandardFacade(
    64  		payload.ComponentName,
    65  		version,
    66  		c.newPublicFacade,
    67  	)
    68  	api.RegisterFacadeVersion(payload.ComponentName, version)
    69  }
    70  
    71  type facadeCaller struct {
    72  	base.FacadeCaller
    73  	closeFunc func() error
    74  }
    75  
    76  func (c facadeCaller) Close() error {
    77  	return c.closeFunc()
    78  }
    79  
    80  func (payloads) newListAPIClient(cmd *status.ListCommand) (status.ListAPI, error) {
    81  	apiCaller, err := cmd.NewAPIRoot()
    82  	if err != nil {
    83  		return nil, errors.Trace(err)
    84  	}
    85  	caller := base.NewFacadeCallerForVersion(apiCaller, payload.ComponentName, 0)
    86  
    87  	listAPI := client.NewPublicClient(&facadeCaller{
    88  		FacadeCaller: caller,
    89  		closeFunc:    apiCaller.Close,
    90  	})
    91  	return listAPI, nil
    92  }
    93  
    94  func (c payloads) registerPublicCommands() {
    95  	if !markRegistered(payload.ComponentName, "public-commands") {
    96  		return
    97  	}
    98  
    99  	commands.RegisterEnvCommand(func() modelcmd.ModelCommand {
   100  		return status.NewListCommand(c.newListAPIClient)
   101  	})
   102  }
   103  
   104  func (c payloads) registerHookContext() {
   105  	if !markRegistered(payload.ComponentName, "hook-context") {
   106  		return
   107  	}
   108  
   109  	unitercontext.RegisterComponentFunc(payload.ComponentName,
   110  		func(config unitercontext.ComponentConfig) (jujuc.ContextComponent, error) {
   111  			hctxClient := c.newUnitFacadeClient(config.APICaller)
   112  			// TODO(ericsnow) Pass the unit's tag through to the component?
   113  			component, err := context.NewContextAPI(hctxClient, config.DataDir)
   114  			if err != nil {
   115  				return nil, errors.Trace(err)
   116  			}
   117  			return component, nil
   118  		},
   119  	)
   120  
   121  	c.registerHookContextCommands()
   122  	c.registerHookContextFacade()
   123  }
   124  
   125  func (payloads) newUnitFacadeClient(caller base.APICaller) context.APIClient {
   126  	facadeCaller := base.NewFacadeCallerForVersion(caller, payloadsHookContextFacade, 0)
   127  	return internalclient.NewUnitFacadeClient(facadeCaller)
   128  }
   129  
   130  func (payloads) newHookContextFacade(st *state.State, unit *state.Unit) (interface{}, error) {
   131  	up, err := st.UnitPayloads(unit)
   132  	if err != nil {
   133  		return nil, errors.Trace(err)
   134  	}
   135  	return internalserver.NewUnitFacade(up), nil
   136  }
   137  
   138  func (c payloads) registerHookContextFacade() {
   139  	const version = 0
   140  	common.RegisterHookContextFacade(
   141  		payloadsHookContextFacade,
   142  		version,
   143  		c.newHookContextFacade,
   144  		reflect.TypeOf(&internalserver.UnitFacade{}),
   145  	)
   146  	api.RegisterFacadeVersion(payloadsHookContextFacade, version)
   147  }
   148  
   149  type payloadsHookContext struct {
   150  	jujuc.Context
   151  }
   152  
   153  // Component implements context.HookContext.
   154  func (c payloadsHookContext) Component(name string) (context.Component, error) {
   155  	found, err := c.Context.Component(name)
   156  	if err != nil {
   157  		return nil, errors.Trace(err)
   158  	}
   159  	compCtx, ok := found.(context.Component)
   160  	if !ok && found != nil {
   161  		return nil, errors.Errorf("wrong component context type registered: %T", found)
   162  	}
   163  	return compCtx, nil
   164  }
   165  
   166  func (payloads) registerHookContextCommands() {
   167  	if !markRegistered(payload.ComponentName, "hook-context-commands") {
   168  		return
   169  	}
   170  
   171  	jujuc.RegisterCommand(context.RegisterCmdName, func(ctx jujuc.Context) (cmd.Command, error) {
   172  		compCtx := payloadsHookContext{ctx}
   173  		cmd, err := context.NewRegisterCmd(compCtx)
   174  		if err != nil {
   175  			return nil, errors.Trace(err)
   176  		}
   177  		return cmd, nil
   178  	})
   179  
   180  	jujuc.RegisterCommand(context.StatusSetCmdName, func(ctx jujuc.Context) (cmd.Command, error) {
   181  		compCtx := payloadsHookContext{ctx}
   182  		cmd, err := context.NewStatusSetCmd(compCtx)
   183  		if err != nil {
   184  			return nil, errors.Trace(err)
   185  		}
   186  		return cmd, nil
   187  	})
   188  
   189  	jujuc.RegisterCommand(context.UnregisterCmdName, func(ctx jujuc.Context) (cmd.Command, error) {
   190  		compCtx := payloadsHookContext{ctx}
   191  		cmd, err := context.NewUnregisterCmd(compCtx)
   192  		if err != nil {
   193  			return nil, errors.Trace(err)
   194  		}
   195  		return cmd, nil
   196  	})
   197  }
   198  
   199  func (payloads) registerState() {
   200  	if !markRegistered(payload.ComponentName, "state") {
   201  		return
   202  	}
   203  
   204  	// TODO(ericsnow) Use a more general registration mechanism.
   205  	//state.RegisterMultiEnvCollections(persistence.Collections...)
   206  
   207  	newUnitPayloads := func(persist state.Persistence, unit, machine string) (state.UnitPayloads, error) {
   208  		return payloadstate.NewUnitPayloads(persist, unit, machine), nil
   209  	}
   210  
   211  	newEnvPayloads := func(persist state.PayloadsEnvPersistence) (state.EnvPayloads, error) {
   212  		envPersist := persistence.NewEnvPersistence(persist)
   213  		envPayloads := payloadstate.EnvPayloads{
   214  			Persist: envPersist,
   215  		}
   216  		return envPayloads, nil
   217  	}
   218  
   219  	state.SetPayloadsComponent(newEnvPayloads, newUnitPayloads)
   220  }