github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/worker/uniter/runner/jujuc/context.go (about)

     1  // Copyright 2012, 2013, 2014 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package jujuc
     5  
     6  import (
     7  	"fmt"
     8  	"strconv"
     9  	"strings"
    10  	"time"
    11  
    12  	"github.com/juju/errors"
    13  	"gopkg.in/juju/charm.v6-unstable"
    14  	"gopkg.in/juju/names.v2"
    15  
    16  	"github.com/juju/juju/apiserver/params"
    17  	"github.com/juju/juju/network"
    18  	"github.com/juju/juju/storage"
    19  )
    20  
    21  // RebootPriority is the type used for reboot requests.
    22  type RebootPriority int
    23  
    24  const (
    25  	// RebootSkip is a noop.
    26  	RebootSkip RebootPriority = iota
    27  	// RebootAfterHook means wait for current hook to finish before
    28  	// rebooting.
    29  	RebootAfterHook
    30  	// RebootNow means reboot immediately, killing and requeueing the
    31  	// calling hook
    32  	RebootNow
    33  )
    34  
    35  // Context is the interface that all hook helper commands
    36  // depend on to interact with the rest of the system.
    37  type Context interface {
    38  	HookContext
    39  	relationHookContext
    40  	actionHookContext
    41  }
    42  
    43  // HookContext represents the information and functionality that is
    44  // common to all charm hooks.
    45  type HookContext interface {
    46  	ContextUnit
    47  	ContextStatus
    48  	ContextInstance
    49  	ContextNetworking
    50  	ContextLeadership
    51  	ContextMetrics
    52  	ContextStorage
    53  	ContextComponents
    54  	ContextRelations
    55  	ContextVersion
    56  }
    57  
    58  // UnitHookContext is the context for a unit hook.
    59  type UnitHookContext interface {
    60  	HookContext
    61  }
    62  
    63  // RelationHookContext is the context for a relation hook.
    64  type RelationHookContext interface {
    65  	HookContext
    66  	relationHookContext
    67  }
    68  
    69  type relationHookContext interface {
    70  	// HookRelation returns the ContextRelation associated with the executing
    71  	// hook if it was found, or an error if it was not found (or is not available).
    72  	HookRelation() (ContextRelation, error)
    73  
    74  	// RemoteUnitName returns the name of the remote unit the hook execution
    75  	// is associated with if it was found, and an error if it was not found or is not
    76  	// available.
    77  	RemoteUnitName() (string, error)
    78  }
    79  
    80  // ActionHookContext is the context for an action hook.
    81  type ActionHookContext interface {
    82  	HookContext
    83  	actionHookContext
    84  }
    85  
    86  type actionHookContext interface {
    87  	// ActionParams returns the map of params passed with an Action.
    88  	ActionParams() (map[string]interface{}, error)
    89  
    90  	// UpdateActionResults inserts new values for use with action-set.
    91  	// The results struct will be delivered to the controller upon
    92  	// completion of the Action.
    93  	UpdateActionResults(keys []string, value string) error
    94  
    95  	// SetActionMessage sets a message for the Action.
    96  	SetActionMessage(string) error
    97  
    98  	// SetActionFailed sets a failure state for the Action.
    99  	SetActionFailed() error
   100  }
   101  
   102  // ContextUnit is the part of a hook context related to the unit.
   103  type ContextUnit interface {
   104  	// UnitName returns the executing unit's name.
   105  	UnitName() string
   106  
   107  	// Config returns the current service configuration of the executing unit.
   108  	ConfigSettings() (charm.Settings, error)
   109  }
   110  
   111  // ContextStatus is the part of a hook context related to the unit's status.
   112  type ContextStatus interface {
   113  	// UnitStatus returns the executing unit's current status.
   114  	UnitStatus() (*StatusInfo, error)
   115  
   116  	// SetUnitStatus updates the unit's status.
   117  	SetUnitStatus(StatusInfo) error
   118  
   119  	// ApplicationStatus returns the executing unit's service status
   120  	// (including all units).
   121  	ApplicationStatus() (ApplicationStatusInfo, error)
   122  
   123  	// SetApplicationStatus updates the status for the unit's service.
   124  	SetApplicationStatus(StatusInfo) error
   125  }
   126  
   127  // ContextInstance is the part of a hook context related to the unit's instance.
   128  type ContextInstance interface {
   129  	// AvailabilityZone returns the executing unit's availability zone or an error
   130  	// if it was not found (or is not available).
   131  	AvailabilityZone() (string, error)
   132  
   133  	// RequestReboot will set the reboot flag to true on the machine agent
   134  	RequestReboot(prio RebootPriority) error
   135  }
   136  
   137  // ContextNetworking is the part of a hook context related to network
   138  // interface of the unit's instance.
   139  type ContextNetworking interface {
   140  	// PublicAddress returns the executing unit's public address or an
   141  	// error if it is not available.
   142  	PublicAddress() (string, error)
   143  
   144  	// PrivateAddress returns the executing unit's private address or an
   145  	// error if it is not available.
   146  	PrivateAddress() (string, error)
   147  
   148  	// OpenPorts marks the supplied port range for opening when the
   149  	// executing unit's service is exposed.
   150  	OpenPorts(protocol string, fromPort, toPort int) error
   151  
   152  	// ClosePorts ensures the supplied port range is closed even when
   153  	// the executing unit's service is exposed (unless it is opened
   154  	// separately by a co- located unit).
   155  	ClosePorts(protocol string, fromPort, toPort int) error
   156  
   157  	// OpenedPorts returns all port ranges currently opened by this
   158  	// unit on its assigned machine. The result is sorted first by
   159  	// protocol, then by number.
   160  	OpenedPorts() []network.PortRange
   161  
   162  	// NetworkConfig returns the network configuration for the unit and the
   163  	// given bindingName.
   164  	//
   165  	// TODO(dimitern): Currently, only the Address is populated, add the
   166  	// rest later.
   167  	//
   168  	// LKK Card: https://canonical.leankit.com/Boards/View/101652562/119258804
   169  	NetworkConfig(bindingName string) ([]params.NetworkConfig, error)
   170  }
   171  
   172  // ContextLeadership is the part of a hook context related to the
   173  // unit leadership.
   174  type ContextLeadership interface {
   175  	// IsLeader returns true if the local unit is known to be leader for at
   176  	// least the next 30s.
   177  	IsLeader() (bool, error)
   178  
   179  	// LeaderSettings returns the current leader settings. Once leader settings
   180  	// have been read in a given context, they will not be updated other than
   181  	// via successful calls to WriteLeaderSettings.
   182  	LeaderSettings() (map[string]string, error)
   183  
   184  	// WriteLeaderSettings writes the supplied settings directly to state, or
   185  	// fails if the local unit is not the service's leader.
   186  	WriteLeaderSettings(map[string]string) error
   187  }
   188  
   189  // ContextMetrics is the part of a hook context related to metrics.
   190  type ContextMetrics interface {
   191  	// AddMetric records a metric to return after hook execution.
   192  	AddMetric(string, string, time.Time) error
   193  }
   194  
   195  // ContextStorage is the part of a hook context related to storage
   196  // resources associated with the unit.
   197  type ContextStorage interface {
   198  	// StorageTags returns a list of tags for storage instances
   199  	// attached to the unit or an error if they are not available.
   200  	StorageTags() ([]names.StorageTag, error)
   201  
   202  	// Storage returns the ContextStorageAttachment with the supplied
   203  	// tag if it was found, and an error if it was not found or is not
   204  	// available to the context.
   205  	Storage(names.StorageTag) (ContextStorageAttachment, error)
   206  
   207  	// HookStorage returns the storage attachment associated
   208  	// the executing hook if it was found, and an error if it
   209  	// was not found or is not available.
   210  	HookStorage() (ContextStorageAttachment, error)
   211  
   212  	// AddUnitStorage saves storage constraints in the context.
   213  	AddUnitStorage(map[string]params.StorageConstraints) error
   214  }
   215  
   216  // ContextComponents exposes modular Juju components as they relate to
   217  // the unit in the context of the hook.
   218  type ContextComponents interface {
   219  	// Component returns the ContextComponent with the supplied name if
   220  	// it was found.
   221  	Component(name string) (ContextComponent, error)
   222  }
   223  
   224  // ContextRelations exposes the relations associated with the unit.
   225  type ContextRelations interface {
   226  	// Relation returns the relation with the supplied id if it was found, and
   227  	// an error if it was not found or is not available.
   228  	Relation(id int) (ContextRelation, error)
   229  
   230  	// RelationIds returns the ids of all relations the executing unit is
   231  	// currently participating in or an error if they are not available.
   232  	RelationIds() ([]int, error)
   233  }
   234  
   235  // ContextComponent is a single modular Juju component as it relates to
   236  // the current unit and hook. Components should implement this interfaces
   237  // in a type-safe way. Ensuring checked type-conversions are preformed on
   238  // the result and value interfaces. You will use the runner.RegisterComponentFunc
   239  // to register a your components concrete ContextComponent implementation.
   240  //
   241  // See: process/context/context.go for an implementation example.
   242  //
   243  type ContextComponent interface {
   244  	// Flush pushes the component's data to Juju state.
   245  	// In the Flush implementation, call your components API.
   246  	Flush() error
   247  }
   248  
   249  // ContextRelation expresses the capabilities of a hook with respect to a relation.
   250  type ContextRelation interface {
   251  
   252  	// Id returns an integer which uniquely identifies the relation.
   253  	Id() int
   254  
   255  	// Name returns the name the locally executing charm assigned to this relation.
   256  	Name() string
   257  
   258  	// FakeId returns a string of the form "relation-name:123", which uniquely
   259  	// identifies the relation to the hook. In reality, the identification
   260  	// of the relation is the integer following the colon, but the composed
   261  	// name is useful to humans observing it.
   262  	FakeId() string
   263  
   264  	// Settings allows read/write access to the local unit's settings in
   265  	// this relation.
   266  	Settings() (Settings, error)
   267  
   268  	// UnitNames returns a list of the remote units in the relation.
   269  	UnitNames() []string
   270  
   271  	// ReadSettings returns the settings of any remote unit in the relation.
   272  	ReadSettings(unit string) (params.Settings, error)
   273  }
   274  
   275  // ContextStorageAttachment expresses the capabilities of a hook with
   276  // respect to a storage attachment.
   277  type ContextStorageAttachment interface {
   278  
   279  	// Tag returns a tag which uniquely identifies the storage attachment
   280  	// in the context of the unit.
   281  	Tag() names.StorageTag
   282  
   283  	// Kind returns the kind of the storage.
   284  	Kind() storage.StorageKind
   285  
   286  	// Location returns the location of the storage: the mount point for
   287  	// filesystem-kind stores, and the device path for block-kind stores.
   288  	Location() string
   289  }
   290  
   291  // ContextVersion expresses the parts of a hook context related to
   292  // reporting workload versions.
   293  type ContextVersion interface {
   294  
   295  	// UnitWorkloadVersion returns the currently set workload version for
   296  	// the unit.
   297  	UnitWorkloadVersion() (string, error)
   298  
   299  	// SetUnitWorkloadVersion updates the workload version for the unit.
   300  	SetUnitWorkloadVersion(string) error
   301  }
   302  
   303  // Settings is implemented by types that manipulate unit settings.
   304  type Settings interface {
   305  	Map() params.Settings
   306  	Set(string, string)
   307  	Delete(string)
   308  }
   309  
   310  // newRelationIdValue returns a gnuflag.Value for convenient parsing of relation
   311  // ids in ctx.
   312  func newRelationIdValue(ctx Context, result *int) (*relationIdValue, error) {
   313  	v := &relationIdValue{result: result, ctx: ctx}
   314  	id := -1
   315  	if r, err := ctx.HookRelation(); err == nil {
   316  		id = r.Id()
   317  		v.value = r.FakeId()
   318  	} else if !errors.IsNotFound(err) {
   319  		return nil, errors.Trace(err)
   320  	}
   321  	*result = id
   322  	return v, nil
   323  }
   324  
   325  // relationIdValue implements gnuflag.Value for use in relation commands.
   326  type relationIdValue struct {
   327  	result *int
   328  	ctx    Context
   329  	value  string
   330  }
   331  
   332  // String returns the current value.
   333  func (v *relationIdValue) String() string {
   334  	return v.value
   335  }
   336  
   337  // Set interprets value as a relation id, if possible, and returns an error
   338  // if it is not known to the system. The parsed relation id will be written
   339  // to v.result.
   340  func (v *relationIdValue) Set(value string) error {
   341  	trim := value
   342  	if idx := strings.LastIndex(trim, ":"); idx != -1 {
   343  		trim = trim[idx+1:]
   344  	}
   345  	id, err := strconv.Atoi(trim)
   346  	if err != nil {
   347  		return fmt.Errorf("invalid relation id")
   348  	}
   349  	if _, err := v.ctx.Relation(id); err != nil {
   350  		return errors.Trace(err)
   351  	}
   352  	*v.result = id
   353  	v.value = value
   354  	return nil
   355  }
   356  
   357  // newStorageIdValue returns a gnuflag.Value for convenient parsing of storage
   358  // ids in ctx.
   359  func newStorageIdValue(ctx Context, result *names.StorageTag) (*storageIdValue, error) {
   360  	v := &storageIdValue{result: result, ctx: ctx}
   361  	if s, err := ctx.HookStorage(); err == nil {
   362  		*v.result = s.Tag()
   363  	} else if !errors.IsNotFound(err) {
   364  		return nil, errors.Trace(err)
   365  	}
   366  	return v, nil
   367  }
   368  
   369  // storageIdValue implements gnuflag.Value for use in storage commands.
   370  type storageIdValue struct {
   371  	result *names.StorageTag
   372  	ctx    Context
   373  }
   374  
   375  // String returns the current value.
   376  func (v *storageIdValue) String() string {
   377  	if *v.result == (names.StorageTag{}) {
   378  		return ""
   379  	}
   380  	return v.result.Id()
   381  }
   382  
   383  // Set interprets value as a storage id, if possible, and returns an error
   384  // if it is not known to the system. The parsed storage id will be written
   385  // to v.result.
   386  func (v *storageIdValue) Set(value string) error {
   387  	if !names.IsValidStorage(value) {
   388  		return errors.Errorf("invalid storage ID %q", value)
   389  	}
   390  	tag := names.NewStorageTag(value)
   391  	if _, err := v.ctx.Storage(tag); err != nil {
   392  		return errors.Trace(err)
   393  	}
   394  	*v.result = tag
   395  	return nil
   396  }