Beispiel #1
0
// wrapper for errorutil that handles missing sources sanely and resets the reader afterwards
func posFromOffset(offset int, source io.ReadSeeker) (int, int, string) {
	if source == nil {
		return 0, 0, ""
	}
	line, col, highlight := errorutil.HighlightBytePosition(source, int64(offset))
	source.Seek(0, 0) // Reset the reader to the start so the next call isn't relative to this position
	return line, col, highlight
}
Beispiel #2
0
func (pm *PodManifest) UnmarshalJSON(data []byte) error {
	p := podManifest(*pm)
	err := json.Unmarshal(data, &p)
	if err != nil {
		if serr, ok := err.(*json.SyntaxError); ok {
			line, col, highlight := errorutil.HighlightBytePosition(bytes.NewReader(data), serr.Offset)
			return fmt.Errorf("\nError at line %d, column %d\n%s%v", line, col, highlight, err)
		}
		return err
	}
	npm := PodManifest(p)
	if err := npm.assertValid(); err != nil {
		return err
	}
	*pm = npm
	return nil
}
Beispiel #3
0
func ParseFromLatest(rawConfig []byte) (config types.Config, err error) {
	if err = json.Unmarshal(rawConfig, &config); err == nil {
		err = config.Ignition.Version.AssertValid()
	} else if isEmpty(rawConfig) {
		err = ErrEmpty
	} else if isCloudConfig(rawConfig) {
		err = ErrCloudConfig
	} else if isScript(rawConfig) {
		err = ErrScript
	}
	if serr, ok := err.(*json.SyntaxError); ok {
		line, col, highlight := errorutil.HighlightBytePosition(bytes.NewReader(rawConfig), serr.Offset)
		err = fmt.Errorf("error at line %d, column %d\n%s%v", line, col, highlight, err)
	}

	return
}
Beispiel #4
0
func (im *ImageManifest) UnmarshalJSON(data []byte) error {
	a := imageManifest(*im)
	err := json.Unmarshal(data, &a)
	if err != nil {
		if serr, ok := err.(*json.SyntaxError); ok {
			line, col, highlight := errorutil.HighlightBytePosition(bytes.NewReader(data), serr.Offset)
			return fmt.Errorf("\nError at line %d, column %d\n%s%v", line, col, highlight, err)
		}
		return err
	}
	nim := ImageManifest(a)
	if err := nim.assertValid(); err != nil {
		return err
	}
	*im = nim
	return nil
}
Beispiel #5
0
// Decodes and evaluates a json config file, watching for include cycles.
func (c *ConfigParser) recursiveReadJSON(configPath string) (decodedObject map[string]interface{}, err error) {
	if configPath != "" {
		absConfigPath, err := filepath.Abs(configPath)
		if err != nil {
			return nil, fmt.Errorf("Failed to expand absolute path for %s", configPath)
		}
		if c.touchedFiles[absConfigPath] {
			return nil, fmt.Errorf("ConfigParser include cycle detected reading config: %v",
				absConfigPath)
		}
		c.touchedFiles[absConfigPath] = true

		c.includeStack.Push(absConfigPath)
		defer c.includeStack.Pop()
	}

	var f File
	if f, err = c.open(configPath); err != nil {
		return nil, fmt.Errorf("Failed to open config: %v", err)
	}
	defer f.Close()

	decodedObject = make(map[string]interface{})
	dj := json.NewDecoder(f)
	if err = dj.Decode(&decodedObject); err != nil {
		extra := ""
		if serr, ok := err.(*json.SyntaxError); ok {
			if _, serr := f.Seek(0, os.SEEK_SET); serr != nil {
				log.Fatalf("seek error: %v", serr)
			}
			line, col, highlight := errorutil.HighlightBytePosition(f, serr.Offset)
			extra = fmt.Sprintf(":\nError at line %d, column %d (file offset %d):\n%s",
				line, col, serr.Offset, highlight)
		}
		return nil, fmt.Errorf("error parsing JSON object in config file %s%s\n%v",
			f.Name(), extra, err)
	}

	if err = c.evaluateExpressions(decodedObject, nil, false); err != nil {
		return nil, fmt.Errorf("error expanding JSON config expressions in %s:\n%v",
			f.Name(), err)
	}

	return decodedObject, nil
}
Beispiel #6
0
func ParseFromLatest(rawConfig []byte) (types.Config, report.Report, error) {
	if isEmpty(rawConfig) {
		return types.Config{}, report.Report{}, ErrEmpty
	} else if isCloudConfig(rawConfig) {
		return types.Config{}, report.Report{}, ErrCloudConfig
	} else if isScript(rawConfig) {
		return types.Config{}, report.Report{}, ErrScript
	}

	var err error
	var config types.Config

	// These errors are fatal and the config should not be further validated
	if err = json.Unmarshal(rawConfig, &config); err == nil {
		versionReport := config.Ignition.Version.Validate()
		if versionReport.IsFatal() {
			return types.Config{}, versionReport, ErrInvalid
		}
	}

	// Handle json syntax and type errors first, since they are fatal but have offset info
	if serr, ok := err.(*json.SyntaxError); ok {
		line, col, highlight := errorutil.HighlightBytePosition(bytes.NewReader(rawConfig), serr.Offset)
		return types.Config{},
			report.Report{
				Entries: []report.Entry{{
					Kind:      report.EntryError,
					Message:   serr.Error(),
					Line:      line,
					Column:    col,
					Highlight: highlight,
				}},
			},
			ErrInvalid
	}

	if terr, ok := err.(*json.UnmarshalTypeError); ok {
		line, col, highlight := errorutil.HighlightBytePosition(bytes.NewReader(rawConfig), terr.Offset)
		return types.Config{},
			report.Report{
				Entries: []report.Entry{{
					Kind:      report.EntryError,
					Message:   terr.Error(),
					Line:      line,
					Column:    col,
					Highlight: highlight,
				}},
			},
			ErrInvalid
	}

	// Handle other fatal errors (i.e. invalid version)
	if err != nil {
		return types.Config{}, report.ReportFromError(err, report.EntryError), err
	}

	// Unmarshal again to a json.Node to get offset information for building a report
	var ast json.Node
	var r report.Report
	configValue := reflect.ValueOf(config)
	if err := json.Unmarshal(rawConfig, &ast); err != nil {
		r.Add(report.Entry{
			Kind:    report.EntryWarning,
			Message: "Ignition could not unmarshal your config for reporting line numbers. This should never happen. Please file a bug.",
		})
		r.Merge(validate.ValidateWithoutSource(configValue))
	} else {
		r.Merge(validate.Validate(configValue, astjson.FromJsonRoot(ast), bytes.NewReader(rawConfig)))
	}

	if r.IsFatal() {
		return types.Config{}, r, ErrInvalid
	}

	return config, r, nil
}