<commit_before>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package exec

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"time"

	"github.com/coreos/ignition/config"
	"github.com/coreos/ignition/config/types"
	"github.com/coreos/ignition/internal/exec/stages"
	"github.com/coreos/ignition/internal/log"
	"github.com/coreos/ignition/internal/providers"
	putil "github.com/coreos/ignition/internal/providers/util"
	"github.com/coreos/ignition/internal/util"
)

const (
	DefaultOnlineTimeout = time.Minute
)

var (
	ErrSchemeUnsupported = errors.New("unsupported url scheme")
	ErrNetworkFailure    = errors.New("network failure")
)

var (
	baseConfig = types.Config{
		Ignition: types.Ignition{Version: types.IgnitionVersion(types.MaxVersion)},
		Storage: types.Storage{
			Filesystems: []types.Filesystem{{
				Name: "root",
				Path: "/sysroot",
			}},
		},
	}
)

// Engine represents the entity that fetches and executes a configuration.
type Engine struct {
	ConfigCache   string
	OnlineTimeout time.Duration
	Logger        *log.Logger
	Root          string
	Provider      providers.Provider
	OemConfig     types.Config
}

// Run executes the stage of the given name. It returns true if the stage
// successfully ran and false if there were any errors.
func (e Engine) Run(stageName string) bool {
	cfg, err := e.acquireConfig()
	switch err {
	case nil:
		e.Logger.PushPrefix(stageName)
		defer e.Logger.PopPrefix()
		return stages.Get(stageName).Create(e.Logger, e.Root).Run(config.Append(config.Append(baseConfig, e.OemConfig), cfg))
	case config.ErrCloudConfig, config.ErrScript, config.ErrEmpty:
		e.Logger.Info("%v: ignoring and exiting...", err)
		return true
	default:
		e.Logger.Crit("failed to acquire config: %v", err)
		return false
	}
}

// acquireConfig returns the configuration, first checking a local cache
// before attempting to fetch it from the provider.
func (e Engine) acquireConfig() (cfg types.Config, err error) {
	// First try read the config @ e.ConfigCache.
	b, err := ioutil.ReadFile(e.ConfigCache)
	if err == nil {
		if err = json.Unmarshal(b, &cfg); err != nil {
			e.Logger.Crit("failed to parse cached config: %v", err)
		}
		return
	}

	// (Re)Fetch the config if the cache is unreadable.
	cfg, err = e.fetchProviderConfig()
	if err != nil {
		e.Logger.Crit("failed to fetch config: %s", err)
		return
	}
	e.Logger.Debug("fetched config: %+v", cfg)

	// Populate the config cache.
	b, err = json.Marshal(cfg)<commit_msg>exec: execute empty user configs<commit_after>// Copyright 2015 CoreOS, Inc.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package exec

import (
	"encoding/json"
	"errors"
	"io/ioutil"
	"net/http"
	"time"

	"github.com/coreos/ignition/config"
	"github.com/coreos/ignition/config/types"
	"github.com/coreos/ignition/internal/exec/stages"
	"github.com/coreos/ignition/internal/log"
	"github.com/coreos/ignition/internal/providers"
	putil "github.com/coreos/ignition/internal/providers/util"
	"github.com/coreos/ignition/internal/util"
)

const (
	DefaultOnlineTimeout = time.Minute
)

var (
	ErrSchemeUnsupported = errors.New("unsupported url scheme")
	ErrNetworkFailure    = errors.New("network failure")
)

var (
	baseConfig = types.Config{
		Ignition: types.Ignition{Version: types.IgnitionVersion(types.MaxVersion)},
		Storage: types.Storage{
			Filesystems: []types.Filesystem{{
				Name: "root",
				Path: "/sysroot",
			}},
		},
	}
)

// Engine represents the entity that fetches and executes a configuration.
type Engine struct {
	ConfigCache   string
	OnlineTimeout time.Duration
	Logger        *log.Logger
	Root          string
	Provider      providers.Provider
	OemConfig     types.Config
}

// Run executes the stage of the given name. It returns true if the stage
// successfully ran and false if there were any errors.
func (e Engine) Run(stageName string) bool {
	cfg, err := e.acquireConfig()
	switch err {
	case config.ErrEmpty, nil:
		e.Logger.PushPrefix(stageName)
		defer e.Logger.PopPrefix()
		return stages.Get(stageName).Create(e.Logger, e.Root).Run(config.Append(config.Append(baseConfig, e.OemConfig), cfg))
	case config.ErrCloudConfig, config.ErrScript:
		e.Logger.Info("%v: ignoring and exiting...", err)
		return true
	default:
		e.Logger.Crit("failed to acquire config: %v", err)
		return false
	}
}

// acquireConfig returns the configuration, first checking a local cache
// before attempting to fetch it from the provider.
func (e Engine) acquireConfig() (cfg types.Config, err error) {
	// First try read the config @ e.ConfigCache.
	b, err := ioutil.ReadFile(e.ConfigCache)
	if err == nil {
		if err = json.Unmarshal(b, &cfg); err != nil {
			e.Logger.Crit("failed to parse cached config: %v", err)
		}
		return
	}

	// (Re)Fetch the config if the cache is unreadable.
	cfg, err = e.fetchProviderConfig()
	if err != nil {
		e.Logger.Crit("failed to fetch config: %s", err)
		return
	}
	e.Logger.Debug("fetched config: %+v", cfg)

	// Populate the config cache.
	b, err = json.Marshal(cfg)
{'fraction_non_alphanumeric': 0.11820135559596627, 'fraction_numerical': 0.002645065300049595, 'mean_word_length': 3.7450980392156863, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2450989', 'n_tokens_mistral': 1981, 'n_tokens_neox': 1889, 'n_words': 595}