// PayloadSchema returns the payload schema for this worker.
func (w *Worker) PayloadSchema() schematypes.Object {
	payloadSchema, err := schematypes.Merge(
		w.tm.engine.PayloadSchema(),
		w.tm.pluginManager.PayloadSchema(),
	)
	if err != nil {
		panic(fmt.Sprintf(
			"Conflicting plugin and engine payload properties, error: %s", err,
		))
	}
	return payloadSchema
}
// NewPluginManager loads all plugins not disabled in configuration and
// returns a Plugin implementation that wraps all of the plugins.
//
// This expects options.Config satisfying schema from
// PluginManagerConfigSchema().
func NewPluginManager(options PluginOptions) (Plugin, error) {
	pluginProviders := Plugins()

	// Construct config schema
	configSchema := PluginManagerConfigSchema()

	// Ensure the config is valid
	if err := configSchema.Validate(options.Config); err != nil {
		return nil, fmt.Errorf("Invalid config, error: %s", err)
	}
	config := options.Config.(map[string]interface{})

	// Find plugins to load
	var enabled []string
	var disabled []string
	if configSchema.Properties["disabled"].Map(config["disabled"], &disabled) != nil {
		panic("internal error -- shouldn't be possible")
	}

	// Find list of enabled plugins and ensure that config is present if required
	for name, plugin := range pluginProviders {
		// Skip disabled plugins
		if stringContains(disabled, name) {
			continue
		}
		// Check that configuration is given if required
		if plugin.ConfigSchema() != nil {
			if _, ok := config[name]; !ok {
				return nil, fmt.Errorf("Missing configuration for plugin: '%s'", name)
			}
		}
		// List plugin as enabled
		enabled = append(enabled, name)
	}

	// Initialize all the plugins
	wg := sync.WaitGroup{}
	plugins := make([]Plugin, len(enabled))
	errors := make([]error, len(enabled))
	wg.Add(len(enabled))
	for index, name := range enabled {
		go func(index int, name string) {
			plugins[index], errors[index] = pluginProviders[name].NewPlugin(PluginOptions{
				Environment: options.Environment,
				Engine:      options.Engine,
				Log:         options.Log.WithField("plugin", name),
				Config:      config[name],
			})
			wg.Done()
		}(index, name) // needed to capture values not variables
	}
	wg.Wait()

	// Return the first error, if any
	for _, e := range errors {
		if e != nil {
			return nil, e
		}
	}

	// Construct payload schema
	schemas := []schematypes.Object{}
	for _, plugin := range plugins {
		schemas = append(schemas, plugin.PayloadSchema())
	}
	schema, err := schematypes.Merge(schemas...)
	if err != nil {
		return nil, fmt.Errorf("Conflicting payload schema types, error: %s", err)
	}

	return &pluginManager{
		plugins:       plugins,
		pluginNames:   enabled,
		payloadSchema: schema,
	}, nil
}
Beispiel #3
0
// prepareStage is where task plugins are prepared and a sandboxbuilder is created.
func (t *TaskRun) prepareStage() error {
	t.log.Debug("Preparing task run")

	// Parse payload
	payload := map[string]interface{}{}
	err := json.Unmarshal([]byte(t.definition.Payload), &payload)
	if err != nil {
		err = engines.NewMalformedPayloadError(fmt.Sprintf("Invalid task payload. %s", err))
		t.context.LogError(err.Error())
		return err
	}

	// Construct payload schema
	payloadSchema, err := schematypes.Merge(
		t.engine.PayloadSchema(),
		t.plugin.PayloadSchema(),
	)
	if err != nil {
		panic(fmt.Sprintf(
			"Conflicting plugin and engine payload properties, error: %s", err,
		))
	}

	// Validate payload against schema
	err = payloadSchema.Validate(payload)
	if err != nil {
		err = engines.NewMalformedPayloadError("Schema violation: ", err)
		t.context.LogError(err.Error())
		return err
	}

	// Create TaskPlugin
	t.taskPlugin, err = t.plugin.NewTaskPlugin(plugins.TaskPluginOptions{
		TaskInfo: &runtime.TaskInfo{
			TaskID: t.TaskID,
			RunID:  t.RunID,
		},
		Payload: t.plugin.PayloadSchema().Filter(payload),
		Log:     t.log.WithField("plugin", "pluginManager"),
	})
	if err != nil {
		// TODO: We need to review all this... t.context.LogError is for task errors
		// hence MalformedPayloadError only, not for internal-errors!!!
		t.context.LogError(err.Error())
		return err
	}

	// Prepare TaskPlugin
	err = t.taskPlugin.Prepare(t.context)
	if err != nil {
		t.context.LogError(fmt.Sprintf("Could not prepare task plugins. %s", err))
		return err
	}

	sandboxBuilder, err := t.engine.NewSandboxBuilder(engines.SandboxOptions{
		TaskContext: t.context,
		Payload:     t.engine.PayloadSchema().Filter(payload),
	})
	t.m.Lock()
	t.sandboxBuilder = sandboxBuilder
	t.m.Unlock()
	if err != nil {
		t.context.LogError(fmt.Sprintf("Could not create task execution environment. %s", err))
		return err
	}

	return nil
}