Exemple #1
0
func Parse(data []byte) (types.Config, report.Report) {
	var cfg types.Config
	var r report.Report

	if err := yaml.Unmarshal(data, &cfg); err != nil {
		return types.Config{}, report.ReportFromError(err, report.EntryError)
	}

	nodes := yaml.UnmarshalToNode(data)
	if nodes == nil {
		r.Add(report.Entry{
			Kind:    report.EntryWarning,
			Message: "Configuration is empty",
		})
		r.Merge(validate.ValidateWithoutSource(reflect.ValueOf(cfg)))
	} else {
		root, err := fromYamlDocumentNode(*nodes)
		if err != nil {
			return types.Config{}, report.ReportFromError(err, report.EntryError)
		}

		r.Merge(validate.Validate(reflect.ValueOf(cfg), root, nil))
	}

	if r.IsFatal() {
		return types.Config{}, r
	}
	return cfg, r
}
Exemple #2
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
}
Exemple #3
0
func ConvertAs2_0_0(in types.Config) (ignTypes.Config, report.Report) {
	out := ignTypes.Config{
		Ignition: ignTypes.Ignition{
			Version: ignTypes.IgnitionVersion{Major: 2, Minor: 0},
		},
	}

	for _, ref := range in.Ignition.Config.Append {
		newRef, err := convertConfigReference(ref)
		if err != nil {
			return ignTypes.Config{}, report.ReportFromError(err, report.EntryError)
		}
		out.Ignition.Config.Append = append(out.Ignition.Config.Append, newRef)
	}

	if in.Ignition.Config.Replace != nil {
		newRef, err := convertConfigReference(*in.Ignition.Config.Replace)
		if err != nil {
			return ignTypes.Config{}, report.ReportFromError(err, report.EntryError)
		}
		out.Ignition.Config.Replace = &newRef
	}

	for _, disk := range in.Storage.Disks {
		newDisk := ignTypes.Disk{
			Device:    ignTypes.Path(disk.Device),
			WipeTable: disk.WipeTable,
		}

		for _, partition := range disk.Partitions {
			size, err := convertPartitionDimension(partition.Size)
			if err != nil {
				return ignTypes.Config{}, report.ReportFromError(err, report.EntryError)
			}
			start, err := convertPartitionDimension(partition.Start)
			if err != nil {
				return ignTypes.Config{}, report.ReportFromError(err, report.EntryError)
			}

			newDisk.Partitions = append(newDisk.Partitions, ignTypes.Partition{
				Label:    ignTypes.PartitionLabel(partition.Label),
				Number:   partition.Number,
				Size:     size,
				Start:    start,
				TypeGUID: ignTypes.PartitionTypeGUID(partition.TypeGUID),
			})
		}

		out.Storage.Disks = append(out.Storage.Disks, newDisk)
	}

	for _, array := range in.Storage.Arrays {
		newArray := ignTypes.Raid{
			Name:   array.Name,
			Level:  array.Level,
			Spares: array.Spares,
		}

		for _, device := range array.Devices {
			newArray.Devices = append(newArray.Devices, ignTypes.Path(device))
		}

		out.Storage.Arrays = append(out.Storage.Arrays, newArray)
	}

	for _, filesystem := range in.Storage.Filesystems {
		newFilesystem := ignTypes.Filesystem{
			Name: filesystem.Name,
			Path: func(p ignTypes.Path) *ignTypes.Path {
				if p == "" {
					return nil
				}

				return &p
			}(ignTypes.Path(filesystem.Path)),
		}

		if filesystem.Mount != nil {
			newFilesystem.Mount = &ignTypes.FilesystemMount{
				Device: ignTypes.Path(filesystem.Mount.Device),
				Format: ignTypes.FilesystemFormat(filesystem.Mount.Format),
			}

			if filesystem.Mount.Create != nil {
				newFilesystem.Mount.Create = &ignTypes.FilesystemCreate{
					Force:   filesystem.Mount.Create.Force,
					Options: ignTypes.MkfsOptions(filesystem.Mount.Create.Options),
				}
			}
		}

		out.Storage.Filesystems = append(out.Storage.Filesystems, newFilesystem)
	}

	for _, file := range in.Storage.Files {
		newFile := ignTypes.File{
			Filesystem: file.Filesystem,
			Path:       ignTypes.Path(file.Path),
			Mode:       ignTypes.FileMode(file.Mode),
			User:       ignTypes.FileUser{Id: file.User.Id},
			Group:      ignTypes.FileGroup{Id: file.Group.Id},
		}

		if file.Contents.Inline != "" {
			newFile.Contents = ignTypes.FileContents{
				Source: ignTypes.Url{
					Scheme: "data",
					Opaque: "," + dataurl.EscapeString(file.Contents.Inline),
				},
			}
		}

		if file.Contents.Remote.Url != "" {
			source, err := url.Parse(file.Contents.Remote.Url)
			if err != nil {
				return ignTypes.Config{}, report.ReportFromError(err, report.EntryError)
			}

			newFile.Contents = ignTypes.FileContents{Source: ignTypes.Url(*source)}
		}

		if newFile.Contents == (ignTypes.FileContents{}) {
			newFile.Contents = ignTypes.FileContents{
				Source: ignTypes.Url{
					Scheme: "data",
					Opaque: ",",
				},
			}
		}

		newFile.Contents.Compression = ignTypes.Compression(file.Contents.Remote.Compression)
		newFile.Contents.Verification = convertVerification(file.Contents.Remote.Verification)

		out.Storage.Files = append(out.Storage.Files, newFile)
	}

	for _, unit := range in.Systemd.Units {
		newUnit := ignTypes.SystemdUnit{
			Name:     ignTypes.SystemdUnitName(unit.Name),
			Enable:   unit.Enable,
			Mask:     unit.Mask,
			Contents: unit.Contents,
		}

		for _, dropIn := range unit.DropIns {
			newUnit.DropIns = append(newUnit.DropIns, ignTypes.SystemdUnitDropIn{
				Name:     ignTypes.SystemdUnitDropInName(dropIn.Name),
				Contents: dropIn.Contents,
			})
		}

		out.Systemd.Units = append(out.Systemd.Units, newUnit)
	}

	for _, unit := range in.Networkd.Units {
		out.Networkd.Units = append(out.Networkd.Units, ignTypes.NetworkdUnit{
			Name:     ignTypes.NetworkdUnitName(unit.Name),
			Contents: unit.Contents,
		})
	}

	for _, user := range in.Passwd.Users {
		newUser := ignTypes.User{
			Name:              user.Name,
			PasswordHash:      user.PasswordHash,
			SSHAuthorizedKeys: user.SSHAuthorizedKeys,
		}

		if user.Create != nil {
			newUser.Create = &ignTypes.UserCreate{
				Uid:          user.Create.Uid,
				GECOS:        user.Create.GECOS,
				Homedir:      user.Create.Homedir,
				NoCreateHome: user.Create.NoCreateHome,
				PrimaryGroup: user.Create.PrimaryGroup,
				Groups:       user.Create.Groups,
				NoUserGroup:  user.Create.NoUserGroup,
				System:       user.Create.System,
				NoLogInit:    user.Create.NoLogInit,
				Shell:        user.Create.Shell,
			}
		}

		out.Passwd.Users = append(out.Passwd.Users, newUser)
	}

	for _, group := range in.Passwd.Groups {
		out.Passwd.Groups = append(out.Passwd.Groups, ignTypes.Group{
			Name:         group.Name,
			Gid:          group.Gid,
			PasswordHash: group.PasswordHash,
			System:       group.System,
		})
	}

	r := validate.ValidateWithoutSource(reflect.ValueOf(out))
	if r.IsFatal() {
		return ignTypes.Config{}, r
	}

	return out, r
}