hooks

package
v0.0.0-...-8223eb1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jan 14, 2020 License: Apache-2.0 Imports: 21 Imported by: 0

README

p2 Hooks

Hooks are code that may execute at predefined moments in the p2 preparer workflow. Hooks are registered in a fashion similar to pods, although several key differences exist between pods, intended as applications, and hooks.

Hooks can be declared and deployed using the p2-hook utility. Here is an example creating and deploying a hook that sets up the right application users before the application is launched. p2-hook can be run on any host with access to the Consul cluster.

$ echo '#!/bin/bash
useradd -D -d /data/pods/$POD_ID $POD_ID
' > ensure_user
$ chmod o+x ensure_user
$ MANIFEST=$(p2-bin2pod ensure_user | jq '.["manifest_path"]')
$ p2-schedule --hook-type before_install $MANIFEST

This hook establishes that the user running your application is present on the host before any launchable begins.

Hook Constraints

Hooks are run as the user running the preparer. This will be root for most installations. Any future authentication mechanism will be required when scheduling hooks as they permit the rapid deployment of code that will execute as root in your cluster. Needless to say, p2 is still in development and we do not recommend deploying it in production yet.

Hooks run with time restrictions. After 30 seconds, the preparer will send the hook SIGTERM and proceed with operations. At 60 seconds if the hook is still running, the preparer will send a SIGKILL.

Finally, hooks cannot alter the execution of the preparer, even if they fail. This is a safety feature similar to the timeouts. This prevents a broken hook from preventing deploys across your cluster.

Fundamental Hooks Design

At its root, p2's hooks are simply a directory of scripts that are executed during the install and launch phases of p2 launchables. Each directory can be populated independently of p2. However, the p2-preparer comes with an option to register all pod manifests and their launchables at /hooks as scripts that will be symlinked into this directory. The option is on by default.

Layout

Values in the /hooks keyspace are mapped to hooks on disk in the following manner. For a key value of /hooks/{event}/{manifest}, every preparer should install a new pod under /data/hooks/pods/{event}/{manifest}. The layout of the pod directory is identical to that of normal applications.

The layout of hooks on disk is somewhat complex, owing to the reuse of the pod design. While somewhat complex, this reuse gives hook implementors all the power of standard p2 ideas. For the most part, clients shouldn't need to understand how p2 lays out hooks on disk.

Instead of setting up runit services for each launch script, p2 instead finds each launch file and symlinks it into the appropriate exec directory. For example, for a hook that adds appropriate sudoers entries given a manifest, if the hook script is in a pod identified as system under a launchable called sudoers, the hook script will be installed at /data/hooks/pods/before_install/system/sudoers/current/bin/launch and it will be symlinked to /data/hooks/exec/before_install/system_sudoers_launch.

For launch directories instead of launch scripts, each launch script will be installed into the event directory as needed.

Documentation

Index

Constants

View Source
const (
	HookEnvVar                = "HOOK"
	HookEventEnvVar           = "HOOK_EVENT"
	HookedNodeEnvVar          = "HOOKED_NODE"
	HookedPodIDEnvVar         = "HOOKED_POD_ID"
	HookedPodHomeEnvVar       = "HOOKED_POD_HOME"
	HookedPodManifestEnvVar   = "HOOKED_POD_MANIFEST"
	HookedConfigPathEnvVar    = "HOOKED_CONFIG_PATH"
	HookedEnvPathEnvVar       = "HOOKED_ENV_PATH"
	HookedConfigDirPathEnvVar = "HOOKED_CONFIG_DIR_PATH"
	HookedSystemPodRootEnvVar = "HOOKED_SYSTEM_POD_ROOT"
	HookedPodUniqueKeyEnvVar  = "HOOKED_POD_UNIQUE_KEY"
	HookedPodReadOnly         = "HOOKED_POD_READ_ONLY"

	DefaultTimeout = 120 * time.Second
)

Variables

View Source
var (
	// PreparerInit hooks run during the initialization of the preparer
	PreparerInit = HookType("preparer_init")
	// BeforeInstall hooks run before the artifact is downloaded and extracted
	BeforeInstall = HookType("before_install")
	// AfterInstall hooks run after we have installed but before we have disabled the old version
	AfterInstall = HookType("after_install")
	// BeforeUninstall happens after shutdown but before uninstall
	BeforeUninstall = HookType("before_uninstall")
	// BeforeLaunch occurs after we have disabled the old version
	BeforeLaunch = HookType("before_launch")
	// AfterLaunch occurs after launch
	AfterLaunch = HookType("after_launch")
	// AfterAuth occurs conditionally when artifact authorization fails
	AfterAuthFail = HookType("after_auth_fail")
)
View Source
var DefaultPath = "/usr/local/p2hooks.d"

DefaultPath is a directory on disk where hooks are installed by default.

Functions

func InstallHookScripts

func InstallHookScripts(dir string, hookPod *pods.Pod, manifest manifest.Manifest, logger logging.Logger) error

Populates the given directory with executor scripts for each launch script of the given pod, which must be installed. Any orphaned executor scripts (from a past install, but no longer present in this pod) will be cleaned out.

func NewContext

func NewContext(dirpath string, podRoot string, logger *logging.Logger, auditLogger AuditLogger) *hookContext

Types

type AuditLogger

type AuditLogger interface {
	// LogSuccess should be invoked on successful events.
	LogSuccess(env *HookExecContext)
	// LogFailure should be called in case of error or timeout. The second parameter may be null.
	LogFailure(env *HookExecContext, err error)

	// Close any references held by this AuditLogger
	Close() error
}

AuditLogger defines a mechanism for logging hook success or failure to a store, such as a file or SQLite

type ErrHookTimeout

type ErrHookTimeout struct {
	Hook HookExecContext
}

ErrHookTimeout is returned when a Hook's execution times out

func (ErrHookTimeout) Error

func (e ErrHookTimeout) Error() string

type FileAuditLogger

type FileAuditLogger struct {
	// contains filtered or unexported fields
}

func NewFileAuditLogger

func NewFileAuditLogger(logger *logging.Logger) *FileAuditLogger

Returns a FileAuditLogger using the given logger

func (*FileAuditLogger) Close

func (al *FileAuditLogger) Close() error

func (*FileAuditLogger) LogFailure

func (al *FileAuditLogger) LogFailure(env *HookExecContext, err error)

func (*FileAuditLogger) LogSuccess

func (al *FileAuditLogger) LogSuccess(env *HookExecContext)

type HookEnv

type HookEnv struct{}

Hook env is a utility for hook writers using Go. This provides useful access to objects exported by the hooks package.

func CurrentEnv

func CurrentEnv() *HookEnv

func (*HookEnv) Config

func (h *HookEnv) Config() (*config.Config, error)

func (*HookEnv) ConfigDirPath

func (h *HookEnv) ConfigDirPath() string

func (*HookEnv) EnvPath

func (h *HookEnv) EnvPath() string

func (*HookEnv) Event

func (h *HookEnv) Event() (HookType, error)

func (*HookEnv) ExitUnlessEvent

func (h *HookEnv) ExitUnlessEvent(types ...HookType) HookType

func (*HookEnv) Manifest

func (h *HookEnv) Manifest() (manifest.Manifest, error)

func (*HookEnv) Node

func (h *HookEnv) Node() (types.NodeName, error)

func (*HookEnv) Pod

func (h *HookEnv) Pod() (*pods.Pod, error)

Initializes a pod based on the hooked pod manifest and the system pod root

func (*HookEnv) PodFromDisk

func (h *HookEnv) PodFromDisk() (*pods.Pod, error)

Initializes a pod from the current_manifest.yaml file in the pod's home directory. This function will error or return an old manifest if run during an inappropriate hook event, use of this function is discouraged in most cases

func (*HookEnv) PodHome

func (h *HookEnv) PodHome() (string, error)

func (*HookEnv) PodID

func (h *HookEnv) PodID() (types.PodID, error)

func (*HookEnv) PodUniqueKey

func (h *HookEnv) PodUniqueKey() (types.PodUniqueKey, error)

func (*HookEnv) PodUniqueName

func (h *HookEnv) PodUniqueName() (string, error)

type HookExecContext

type HookExecContext struct {
	Path    string // path to hook's executable
	Name    string // human-readable name of Hook
	Timeout time.Duration
	// contains filtered or unexported fields
}

func NewHookExecContext

func NewHookExecContext(path string, name string, timeout time.Duration, env HookExecutionEnvironment, logger logging.Logger) *HookExecContext

func (*HookExecContext) Close

func (hec *HookExecContext) Close()

Close any references held by this HookExecContext

func (*HookExecContext) Run

func (h *HookExecContext) Run(logger logging.Logger) error

Run executes the hook in the context of its environment and logs the output

func (*HookExecContext) RunWithTimeout

func (h *HookExecContext) RunWithTimeout(logger logging.Logger) error

RunWithTimeout runs the hook but returns a HookTimeoutError when it exceeds its timeout

Necessary because Run() hangs if the command double-forks without properly re-opening its fd's and exec.Start() will dutifully wait on any unclosed fd

NB: in the event of a timeout this will leak descriptors

type HookExecutionEnvironment

type HookExecutionEnvironment struct {
	HookEnvVar,
	HookEventEnvVar,
	HookedNodeEnvVar,
	HookedPodIDEnvVar,
	HookedPodHomeEnvVar,
	HookedPodManifestEnvVar,
	HookedConfigPathEnvVar,
	HookedEnvPathEnvVar,
	HookedConfigDirPathEnvVar,
	HookedSystemPodRootEnvVar,
	HookedPodUniqueKeyEnvVar,
	HookedPodReadOnly string
}

The set of environment variables exposed to the hook as it runs TODO Need this be public?

func (*HookExecutionEnvironment) Env

func (hee *HookExecutionEnvironment) Env() []string

The set of UNIX environment variables for the hook's execution

type HookType

type HookType string

HookType represents the stage in the Hook lifecycle

func AsHookType

func AsHookType(value string) (HookType, error)

func (HookType) String

func (hookType HookType) String() string

type Pod

type Pod interface {
	ConfigDir() string
	EnvDir() string
	Node() types.NodeName
	Home() string
	UniqueKey() types.PodUniqueKey
	ReadOnly() bool
}

Pod is the minimum set of functions needed for a hook to operate on a Pod

type RunHookResult

type RunHookResult struct {
	Err error
}

RunHookResult holds the hook run result data

type SQLiteAuditLogger

type SQLiteAuditLogger struct {
	// contains filtered or unexported fields
}

func NewSQLiteAuditLogger

func NewSQLiteAuditLogger(sqliteDBPath string, logger *logging.Logger) (*SQLiteAuditLogger, error)

func (*SQLiteAuditLogger) Close

func (al *SQLiteAuditLogger) Close() error

Close will terminate this AuditLogger. Re-establishing the connection is not supported, use the constructor.

func (*SQLiteAuditLogger) LogFailure

func (al *SQLiteAuditLogger) LogFailure(ctx *HookExecContext, err error)

func (*SQLiteAuditLogger) LogSuccess

func (al *SQLiteAuditLogger) LogSuccess(ctx *HookExecContext)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL