Пример #1
0
func (engineProvider) NewEngine(options engines.EngineOptions) (engines.Engine, error) {
	var c config
	if schematypes.MustMap(configSchema, options.Config, &c) != nil {
		return nil, engines.ErrContractViolation
	}

	// Load user-groups
	groups := []*system.Group{}
	for _, name := range c.Groups {
		group, err := system.FindGroup(name)
		if err != nil {
			return nil, fmt.Errorf(
				"Unable to find system user-group: %s from engine config, error: %s",
				name, err,
			)
		}
		groups = append(groups, group)
	}

	return &engine{
		environment: options.Environment,
		log:         options.Log,
		config:      c,
		groups:      groups,
	}, nil
}
Пример #2
0
func (p *plugin) NewTaskPlugin(options plugins.TaskPluginOptions) (
	plugins.TaskPlugin, error,
) {
	var P payload
	if schematypes.MustMap(p.PayloadSchema(), options.Payload, &P) != nil {
		return nil, engines.ErrContractViolation
	}
	// If not always enabled or no options are given then this is disabled
	if P.Interactive == nil && !p.config.AlwaysEnabled {
		return nil, nil
	}

	// Extract options
	o := opts{}
	if P.Interactive != nil {
		o = *P.Interactive
	}
	if o.ArtifactPrefix == "" || p.config.ForbidCustomArtifactPrefix {
		o.ArtifactPrefix = p.config.ArtifactPrefix
	}

	return &taskPlugin{
		opts:   o,
		log:    options.Log,
		parent: p,
	}, nil
}
Пример #3
0
func (e engineProvider) NewEngine(options engines.EngineOptions) (engines.Engine, error) {
	var c configType
	if err := schematypes.MustMap(configSchema, options.Config, &c); err != nil {
		options.Log.WithError(err).Error("Invalid configuration")
		return nil, engines.ErrContractViolation
	}

	return &engine{
		config: &c,
		log:    options.Log,
	}, nil
}
Пример #4
0
func (e *engine) NewSandboxBuilder(options engines.SandboxOptions) (engines.SandboxBuilder, error) {
	var p payload
	if schematypes.MustMap(payloadSchema, options.Payload, &p) != nil {
		return nil, engines.ErrContractViolation
	}
	b := &sandboxBuilder{
		engine:  e,
		payload: p,
		context: options.TaskContext,
		env:     make(map[string]string),
		log: e.log.
			WithField("taskId", options.TaskContext.TaskID).
			WithField("runId", options.TaskContext.RunID),
	}
	go b.fetchContext()
	return b, nil
}
Пример #5
0
func (e *engine) NewSandboxBuilder(options engines.SandboxOptions) (engines.SandboxBuilder, error) {
	var p payloadType
	if schematypes.MustMap(payloadSchema, options.Payload, &p) != nil {
		return nil, engines.ErrContractViolation
	}

	// Get an idle network
	net, err := e.networkPool.Network()
	if err == network.ErrAllNetworksInUse {
		return nil, engines.ErrMaxConcurrencyExceeded
	}
	if err != nil {
		return nil, err
	}

	// Create sandboxBuilder, it'll handle image downloading
	return newSandboxBuilder(&p, net, options.TaskContext, e), nil
}
Пример #6
0
func (provider) NewPlugin(options plugins.PluginOptions) (plugins.Plugin, error) {
	var c config
	if schematypes.MustMap(configSchema, options.Config, &c) != nil {
		return nil, engines.ErrContractViolation
	}
	if c.ArtifactPrefix == "" {
		c.ArtifactPrefix = defaultArtifactPrefix
	}
	if c.ShellToolURL == "" {
		c.ShellToolURL = defaultShellToolURL
	}
	if c.DisplayToolURL == "" {
		c.DisplayToolURL = defaultDisplayToolURL
	}
	return &plugin{
		config: c,
		log:    options.Log,
	}, nil
}
Пример #7
0
func (engineProvider) NewEngine(options engines.EngineOptions) (engines.Engine, error) {
	var config configType
	if schematypes.MustMap(configSchema, options.Config, &config) != nil {
		return nil, engines.ErrContractViolation
	}
	// Construct payload schema as schematypes.Object using schema.properties
	properties := schematypes.Properties{}
	for k, s := range config.Schema.Properties {
		schema, err := schematypes.NewSchema(s)
		if err != nil {
			return nil, fmt.Errorf("Error loading schema: %s", err)
		}
		properties[k] = schema
	}

	return &engine{
		Log:    options.Log,
		config: config,
		schema: schematypes.Object{
			Properties: properties,
		},
		environment: options.Environment,
	}, nil
}
Пример #8
0
// New will create a worker given configuration matching the schema from
// ConfigSchema(). The log parameter is optional and if nil is given a default
// logrus logger will be used.
func New(config interface{}, log *logrus.Logger) (*Worker, error) {
	// Validate and map configuration to c
	var c configType
	if err := schematypes.MustMap(ConfigSchema(), config, &c); err != nil {
		return nil, fmt.Errorf("Invalid configuration: %s", err)
	}

	// Create temporary folder
	err := os.RemoveAll(c.TemporaryFolder)
	if err != nil {
		return nil, fmt.Errorf("Failed to remove temporaryFolder: %s, error: %s",
			c.TemporaryFolder, err)
	}
	tempStorage, err := runtime.NewTemporaryStorage(c.TemporaryFolder)
	if err != nil {
		return nil, fmt.Errorf("Failed to create temporary folder, error: %s", err)
	}

	// Create logger
	if log == nil {
		log = logrus.New()
	}
	log.Level, _ = logrus.ParseLevel(c.LogLevel)

	// Setup WebHookServer
	localServer, err := webhookserver.NewLocalServer(
		net.ParseIP(c.ServerIP), c.ServerPort,
		c.NetworkInterface, c.ExposedPort,
		c.DNSDomain,
		c.DNSSecret,
		c.TLSCertificate,
		c.TLSKey,
		time.Duration(c.MaxLifeCycle)*time.Second,
	)
	if err != nil {
		return nil, err
	}

	// Create environment
	gc := gc.New(c.TemporaryFolder, c.MinimumDiskSpace, c.MinimumMemory)
	env := &runtime.Environment{
		GarbageCollector: gc,
		Log:              log,
		TemporaryStorage: tempStorage,
		WebHookServer:    localServer,
	}

	// Ensure that engine confiuguration was provided for the engine selected
	if _, ok := c.Engines[c.Engine]; !ok {
		return nil, fmt.Errorf("Invalid configuration: The key 'engines.%s' must "+
			"be specified when engine '%s' is selected", c.Engine, c.Engine)
	}

	// Find engine provider (schema should ensure it exists)
	provider := engines.Engines()[c.Engine]
	engine, err := provider.NewEngine(engines.EngineOptions{
		Environment: env,
		Log:         env.Log.WithField("engine", c.Engine),
		Config:      c.Engines[c.Engine],
	})
	if err != nil {
		return nil, fmt.Errorf("Engine initialization failed, error: %s", err)
	}

	// Initialize plugin manager
	pm, err := plugins.NewPluginManager(plugins.PluginOptions{
		Environment: env,
		Engine:      engine,
		Log:         env.Log.WithField("plugin", "plugin-manager"),
		Config:      c.Plugins,
	})
	if err != nil {
		return nil, fmt.Errorf("Plugin initialization failed, error: %s", err)
	}

	tm, err := newTaskManager(
		&c, engine, pm, env,
		env.Log.WithField("component", "task-manager"), gc,
	)
	if err != nil {
		return nil, err
	}

	return &Worker{
		log:    env.Log.WithField("component", "worker"),
		tm:     tm,
		sm:     runtime.NewShutdownManager("local"),
		env:    env,
		server: localServer,
		done:   make(chan struct{}),
	}, nil
}
Пример #9
0
// Load configuration from YAML config object.
func Load(data []byte) (map[string]interface{}, error) {
	// Parse config file
	var config interface{}
	err := yaml.Unmarshal(data, &config)
	if err != nil {
		return nil, fmt.Errorf("Failed to parse YAML config, error: %s", err)
	}
	// This fixes obscurities in yaml.Unmarshal where it generates
	// map[interface{}]interface{} instead of map[string]interface{}
	// credits: https://github.com/go-yaml/yaml/issues/139#issuecomment-220072190
	config = convertSimpleJSONTypes(config)

	// Extract transforms and config
	c, ok := config.(map[string]interface{})
	if !ok {
		return nil, fmt.Errorf("Expected top-level config value to be an object")
	}
	result, ok := c["config"].(map[string]interface{})
	if !ok {
		return nil, fmt.Errorf("Expected 'config' property to be an object")
	}

	// Ensure that we have a simple JSON compatible structure
	if err := jsonCompatTypes(result); err != nil {
		panic(fmt.Sprintf("YAML loaded wrong types, error: %s", err))
	}

	// Apply transforms
	if ct, ok := c["transforms"]; ok {
		var transforms []string
		err := schematypes.MustMap(Schema().Properties["transforms"], ct, &transforms)
		if err != nil {
			return nil, fmt.Errorf("'transforms' schema violated, error: %s", err)
		}

		providers := Providers()
		for _, t := range transforms {
			provider, ok := providers[t]
			if !ok {
				return nil, fmt.Errorf("Unknown config transformation: %s", t)
			}
			if err := provider.Transform(result); err != nil {
				return nil, fmt.Errorf("Config transformation: %s failed error: %s",
					t, err)
			}

			// Ensure that transform only injects simple JSON compatible types
			if err := jsonCompatTypes(result); err != nil {
				panic(fmt.Sprintf("%s injected wrong types, error: %s", t, err))
			}
		}
	}

	// Filter out keys that aren't in the config schema...
	// This way extra keys can be used to provide options for the
	// transformations, like "secrets" which will use the secretsBaseUrl if
	// present in the configuration.
	worker.ConfigSchema().Filter(result)

	// Validate against worker schema
	if err := worker.ConfigSchema().Validate(result); err != nil {
		return nil, err
	}

	return result, nil
}