// 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 }
// 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 }