Skip to content
This repository was archived by the owner on Jan 21, 2020. It is now read-only.
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 11 additions & 3 deletions cmd/cli/plugin.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func pluginCommand(plugins func() discovery.Plugins) *cobra.Command {
}

configURL := start.Flags().String("config-url", "", "URL for the startup configs")
osExec := start.Flags().Bool("os", false, "True to use os plugin binaries")
executor := start.Flags().String("exec", "os", "Executor to use for starting up plugins: [os | docker-run]")
doWait := start.Flags().BoolP("wait", "w", false, "True to wait in the foreground; Ctrl-C to exit")

start.RunE = func(c *cobra.Command, args []string) error {
Expand All @@ -79,8 +79,16 @@ func pluginCommand(plugins func() discovery.Plugins) *cobra.Command {

monitors := []*launch.Monitor{}

if *osExec {
exec, err := os.NewLauncher()
switch *executor {
case "os":
exec, err := os.NewLauncher("os")
if err != nil {
return err
}
monitors = append(monitors, launch.NewMonitor(exec, parsedRules))
case "docker-run":
// docker-run is also implemented by the same os executor. We just search for a different key (docker-run)
exec, err := os.NewLauncher("docker-run")
if err != nil {
return err
}
Expand Down
15 changes: 5 additions & 10 deletions examples/flavor/swarm/e2e-plugins.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@
{
"Plugin" : "group-default",
"Launch" : {
"Exec" : "os",
"Properties": {
"os": {
"Cmd" : "infrakit-group-default --poll-interval 500ms --name group-stateless --log 5 > {{env "LOG_DIR"}}/group-default-{{unixtime}}.log 2>&1 &",
"SamePgID" : true
}
Expand All @@ -13,8 +12,7 @@
{
"Plugin" : "instance-file",
"Launch" : {
"Exec" : "os",
"Properties" : {
"os" : {
"Cmd" : "infrakit-instance-file --dir {{env "TUTORIAL_DIR"}} --log 5 > {{env "LOG_DIR"}}/instance-file-{{unixtime}}.log 2>&1",
"SamePgID" : true
}
Expand All @@ -24,8 +22,7 @@
{
"Plugin" : "instance-vagrant",
"Launch" : {
"Exec" : "os",
"Properties" : {
"os" : {
"Cmd" : "infrakit-instance-vagrant --log 5 > {{env "LOG_DIR"}}/instance-vagrant-{{unixtime}}.log 2>&1",
"SamePgID" : true
}
Expand All @@ -35,8 +32,7 @@
{
"Plugin" : "flavor-vanilla",
"Launch" : {
"Exec" : "os",
"Properties" : {
"os" : {
"Cmd" : "infrakit-flavor-vanilla --log 5 > {{env "LOG_DIR"}}/flavor-vanilla-{{unixtime}}.log 2>&1",
"SamePgID" : true
}
Expand All @@ -46,8 +42,7 @@
{
"Plugin" : "flavor-swarm",
"Launch" : {
"Exec" : "os",
"Properties" : {
"os" : {
"Cmd" : "infrakit-flavor-swarm --host {{env "SWARM_MANAGER"}} --log 5 > {{env "LOG_DIR"}}/flavor-swarm-{{unixtime}}.log 2>&1",
"SamePgID" : true
}
Expand Down
37 changes: 17 additions & 20 deletions pkg/launch/monitor.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,29 +11,25 @@ import (

var errNoConfig = errors.New("no-config")

// ExecRule encapsulates what's required to exec a plugin
type ExecRule struct {
// Exec is the name of the exec to use to start the plugin
Exec string
// Properties is the properties for the executor
Properties *types.Any
}
// ExecName is the name of the executor to use (e.g. 'os', 'docker-run', etc.). It's found in the config.
type ExecName string

// Rule provides the instructions on starting the plugin
type Rule struct {

// Plugin is the name of the plugin
Plugin plugin.Name

// Launch is the rule for starting / launching the plugin.
Launch ExecRule
// Launch is the rule for starting / launching the plugin. It's a dictionary with the key being
// the name of the executor and the value being the properties used by that executor.
Launch map[ExecName]*types.Any
}

// Monitor runs continuously receiving requests to start a plugin.
// Monitor uses a launcher to actually start the process of the plugin.
type Monitor struct {
exec Exec
rules map[plugin.Name]Rule
rules map[plugin.Name]*types.Any
startChan <-chan StartPlugin
inputChan chan<- StartPlugin
stop chan interface{}
Expand All @@ -42,12 +38,13 @@ type Monitor struct {

// NewMonitor returns a monitor that continuously watches for input
// requests and launches the process for the plugin, if not already running.
// The configuration to use in the config is matched to the Name() of the executor (the field Exec).
func NewMonitor(l Exec, rules []Rule) *Monitor {
m := map[plugin.Name]Rule{}
m := map[plugin.Name]*types.Any{}
// index by name of plugin
for _, r := range rules {
if r.Launch.Exec == l.Name() {
m[r.Plugin] = r
if cfg, has := r.Launch[ExecName(l.Name())]; has {
m[r.Plugin] = cfg
}
}
return &Monitor{
Expand Down Expand Up @@ -100,30 +97,30 @@ func (m *Monitor) Start() (chan<- StartPlugin, error) {
}

// match first by full name of the form lookup/type -- 'specialization'
r, has := m.rules[req.Plugin]
properties, has := m.rules[req.Plugin]
if !has {
// match now by lookup only -- 'base class'
alternate, _ := req.Plugin.GetLookupAndType()
r, has = m.rules[plugin.Name(alternate)]
properties, has = m.rules[plugin.Name(alternate)]
}
if !has {
log.Warningln("no plugin:", req)
req.reportError(r.Launch.Properties, errNoConfig)
req.reportError(nil, errNoConfig)
continue loop
}

configCopy := types.AnyBytes(nil)
if r.Launch.Properties != nil {
*configCopy = *r.Launch.Properties
if properties != nil {
*configCopy = *properties
}

block, err := m.exec.Exec(r.Plugin.String(), configCopy)
block, err := m.exec.Exec(req.Plugin.String(), configCopy)
if err != nil {
req.reportError(configCopy, err)
continue loop
}

log.Infoln("Waiting for", r.Plugin, "to start:", configCopy.String())
log.Infoln("Waiting for", req.Plugin, "to start:", configCopy.String())
err = <-block
if err != nil {
req.reportError(configCopy, err)
Expand Down
10 changes: 4 additions & 6 deletions pkg/launch/monitor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,9 +69,8 @@ func TestMonitorLoopValidRule(t *testing.T) {
var receivedArgs *types.Any
rule := Rule{
Plugin: "hello",
Launch: ExecRule{
Exec: "test",
Properties: types.AnyValueMust(config),
Launch: map[ExecName]*types.Any{
"test": types.AnyValueMust(config),
},
}
monitor := NewMonitor(&testLauncher{
Expand Down Expand Up @@ -112,9 +111,8 @@ func TestMonitorLoopRuleLookupBehavior(t *testing.T) {
var receivedArgs *types.Any
rule := Rule{
Plugin: "hello",
Launch: ExecRule{
Exec: "test",
Properties: types.AnyValueMust(config),
Launch: map[ExecName]*types.Any{
"test": types.AnyValueMust(config),
},
}
monitor := NewMonitor(&testLauncher{
Expand Down
6 changes: 4 additions & 2 deletions pkg/launch/os/os.go
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,9 @@ type LaunchConfig struct {

// NewLauncher returns a Launcher that can install and start plugins. The OS version is simple - it translates
// plugin names as command names and uses os.Exec
func NewLauncher() (*Launcher, error) {
func NewLauncher(n string) (*Launcher, error) {
return &Launcher{
name: n,
plugins: map[string]state{},
}, nil
}
Expand All @@ -31,13 +32,14 @@ type state struct {

// Launcher is a service that implements the launch.Exec interface for starting up os processes.
type Launcher struct {
name string
plugins map[string]state
lock sync.Mutex
}

// Name returns the name of the launcher
func (l *Launcher) Name() string {
return "os"
return l.name
}

// Exec starts the os process. Returns a signal channel to block on optionally.
Expand Down
4 changes: 2 additions & 2 deletions pkg/launch/os/os_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ import (

func TestLaunchOSCommand(t *testing.T) {

launcher, err := NewLauncher()
launcher, err := NewLauncher("os")
require.NoError(t, err)

starting, err := launcher.Exec("sleepPlugin", types.AnyValueMust(&LaunchConfig{
Expand All @@ -30,7 +30,7 @@ func TestLaunchWithLog(t *testing.T) {

logfile := filepath.Join(os.TempDir(), fmt.Sprintf("os-test-%v", time.Now().Unix()))

launcher, err := NewLauncher()
launcher, err := NewLauncher("os")
require.NoError(t, err)

starting, err := launcher.Exec("echoPlugin", types.AnyValueMust(&LaunchConfig{
Expand Down
45 changes: 28 additions & 17 deletions scripts/e2e-test-plugins.json
Original file line number Diff line number Diff line change
@@ -1,55 +1,66 @@
{{define "rundocker"}}docker run -d --restart always -e INFRAKIT_HOME=/infrakit -e INFRAKIT_PLUGINS_DIR=/infrakit/plugins -v ~/.infrakit:/infrakit --name {{.}} infrakit/devbundle{{end}}
[
{
"Plugin" : "group-default",
"Plugin" : "group-stateless",
"Launch" : {
"Exec" : "os",
"Properties": {
"Cmd" : "infrakit-group-default --poll-interval 500ms --name group-stateless --log 5 > {{env "LOG_DIR"}}/group-default-{{unixtime}}.log 2>&1 &",
"os": {
"Cmd" : "infrakit-group-default --poll-interval 500ms --name group-stateless --log 5 > {{env "INFRAKIT_HOME"}}/logs/group-stateless.log 2>&1",
"SamePgID" : true
}
},
"docker-run" : {
"Cmd" : "{{template "rundocker" "group-stateless"}} infrakit-group-default --poll-interval 500ms --name group-stateless --log 5"
}
}
}
,
{
"Plugin" : "instance-file",
"Launch" : {
"Exec" : "os",
"Properties" : {
"Cmd" : "infrakit-instance-file --dir {{env "TUTORIAL_DIR"}} --log 5 > {{env "LOG_DIR"}}/instance-file-{{unixtime}}.log 2>&1",
"os" : {
"Cmd" : "infrakit-instance-file --dir {{env "INFRAKIT_HOME"}}/instance-file --log 5 > {{env "INFRAKIT_HOME"}}/logs/instance-file.log 2>&1",
"SamePgID" : true
},
"docker-run" : {
"Cmd" : "{{template "rundocker" "instance-file"}} infrakit-instance-file --dir {{env "INFRAKIT_HOME"}}/instance-file --log 5"
}
}
}
,
{
"Plugin" : "instance-vagrant",
"Launch" : {
"Exec" : "os",
"Properties" : {
"Cmd" : "infrakit-instance-vagrant --log 5 > {{env "LOG_DIR"}}/instance-vagrant-{{unixtime}}.log 2>&1",
"os" : {
"Cmd" : "infrakit-instance-vagrant --log 5 > {{env "INFRAKIT_HOME"}}/logs/instance-vagrant.log 2>&1",
"SamePgID" : true
},
"docker-run" : {
"Cmd" : "{{template "rundocker" "instance-vagrant"}} infrakit-instance-vagrant --log 5"
}
}
}
,
{
"Plugin" : "flavor-vanilla",
"Launch" : {
"Exec" : "os",
"Properties" : {
"Cmd" : "infrakit-flavor-vanilla --log 5 > {{env "LOG_DIR"}}/flavor-vanilla-{{unixtime}}.log 2>&1",
"os" : {
"Cmd" : "infrakit-flavor-vanilla --log 5 > {{env "INFRAKIT_HOME"}}/logs/flavor-vanilla.log 2>&1",
"SamePgID" : true
},
"docker-run" : {
"Cmd" : "{{template "rundocker" "flavor-vanilla"}} infrakit-flavor-vanilla --log 5"
}
}
}
,
{
"Plugin" : "flavor-swarm",
"Launch" : {
"Exec" : "os",
"Properties" : {
"Cmd" : "infrakit-flavor-swarm --host {{env "SWARM_MANAGER"}} --log 5 > {{env "LOG_DIR"}}/flavor-swarm-{{unixtime}}.log 2>&1",
"os" : {
"Cmd" : "infrakit-flavor-swarm --host {{env "SWARM_MANAGER"}} --log 5 > {{env "INFRAKIT_HOME"}}/logs/flavor-swarm.log 2>&1",
"SamePgID" : true
},
"docker-run" : {
"Cmd" : "{{template "rundocker" "flavor-swarm"}} infrakit-flavor-swarm --host {{env "SWARM_MANAGER"}} --log 5"
}
}
}
Expand Down
24 changes: 13 additions & 11 deletions scripts/e2e-test.sh
Original file line number Diff line number Diff line change
Expand Up @@ -24,16 +24,19 @@ cleanup() {
trap cleanup EXIT

# infrakit directories
plugins=~/.infrakit/plugins

export INFRAKIT_HOME=~/.infrakit

plugins=$INFRAKIT_HOME/plugins
mkdir -p $plugins
rm -rf $plugins/*

configstore=~/.infrakit/configs
configstore=$INFRAKIT_HOME/configs
mkdir -p $configstore
rm -rf $configstore/*

# set the leader -- for os / file based leader detection for manager
leaderfile=~/.infrakit/leader
leaderfile=$INFRAKIT_HOME/leader
echo group > $leaderfile

# start up multiple instances of manager -- typically we want multiple SETS of plugins and managers
Expand All @@ -46,19 +49,18 @@ sleep 5 # manager needs to detect leadership

# location of logfiles when plugins are started by the plugin cli
# the config json below expects LOG_DIR as an environment variable
LOG_DIR=~/.infrakit/logs
LOG_DIR=$INFRAKIT_HOME/logs
mkdir -p $LOG_DIR

# see the config josn 'e2e-test-plugins.json' for reference of environment variable TUTORIAL_DIR
TUTORIAL_DIR=~/.infrakit/tutorial
mkdir -p $TUTORIAL_DIR
rm -rf $TUTORIAL_DIR/*
# see the config josn 'e2e-test-plugins.json' for reference of environment variable
INSTANCE_FILE_DIR=$INFRAKIT_HOME/instance-file
mkdir -p $INSTANCE_FILE_DIR
rm -rf $INSTANCE_FILE_DIR/*

export LOG_DIR=$LOG_DIR
export TUTORIAL_DIR=$TUTORIAL_DIR

# note -- on exit, this won't clean up the plugins started by the cli since they will be in a separate process group
infrakit plugin start --wait --config-url file:///$PWD/scripts/e2e-test-plugins.json --os group-default instance-file flavor-vanilla &
infrakit plugin start --wait --config-url file:///$PWD/scripts/e2e-test-plugins.json --exec os group-stateless instance-file flavor-vanilla &

starterpid=$!
echo "plugin start pid=$starterpid"
Expand Down Expand Up @@ -130,7 +132,7 @@ sleep 5
expect_output_lines "10 instances should exist in group" "infrakit group describe cattle -q" "10"

# Terminate 3 instances.
pushd $TUTORIAL_DIR
pushd $INSTANCE_FILE_DIR
rm $(ls | head -3)
popd

Expand Down