uci

package module
v0.0.0-...-6eacf8f Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jul 18, 2019 License: MIT Imports: 11 Imported by: 0

README

go-uci

WORK IN PROGRESS

GoDoc CircleCI Codecov

UCI is OpenWRT's Unified Configuration Interface. It is used to configure OpenWRT router hardware using a simple DSL (and acompanying CLI tools). Configuration files are written into a central directory (/etc/config/*) which basically represents a key/value store.

This project makes it easy to interact with such a config tree by providing a native interface to that KV store. It has no external runtime dependencies.

For now, we only implements a superset of the actual UCI DSL, but improvements (patches or PRs) are very welcome. Refer to Rob Pike's Lexical Scanning in Go for implementation details on the parser/lexer.

Why?

We're currently experimenting with Go binaries on OpenWRT router hardware and need a way to interact with the system configuration. We could have created bindings for libuci, but the turnaround cycle in developing with CGO is a bit tedious. Also, since Go does not compile for our target platforms, we need to resort to GCCGO, which has other quirks.

The easiest solution therefore is a plain Go library, which can be used in Go (with or without CGO) and GCCGO without worrying about interoperability. A library also allows UCI to be used outside of OpenWRT systems (e.g. for provisioning).

Usage

import "github.com/digineo/go-uci"

func main() {
    // use the default tree (/etc/config)
    if values, ok := u.Get("system", "@system[0]", "hostname"); ok {
        fmt.Println("hostanme", values)
        //=> hostname [OpenWRT]
    }

    // use a custom tree
    u := uci.NewTree("/path/to/config")
    if values, ok := u.Get("network", "lan", "ifname"); ok {
        fmt.Println("network.lan.ifname", values)
        //=> network.lan.ifname [eth0.2]
    }
    if sectionExists := u.Set("network", "lan", "ipaddr", "192.168.7.1"); !sectionExists {
        _ = u.AddSection("network", "lan", "interface")
        _ = u.Set("network", "lan", "ipaddr", "192.168.7.1")
    }
    u.Commit() // or uci.Revert()
}

See API documentation for more details.

Contributing

Pull requests are welcome, especially if they increase test coverage.

Before submitting changes, please make sure the tests still pass:

$ go test github.com/digineo/go-uci/...

License

MIT License. Copyright (c) 2019 Dominik Menke, Digineo GmbH

https://www.digineo.de

See LICENSE file for details.

Documentation

Overview

Package uci implements a binding to OpenWRT's UCI (Unified Configuration Interface) files in pure Go.

The typical use case is reading and modifying UCI config options:

import "github.com/digineo/go-uci"

uci.Get("network", "lan", "ifname") //=> []string{"eth0.1"}, true
uci.Set("network", "lan", "ipaddr", "192.168.7.1")
uci.Commit() // or uci.Revert()

For more details head over to the OpenWRT wiki, or dive into UCI's C source code:

The lexer is heavily inspired by Rob Pike's 2011 GTUG Sydney talk "Lexical Scanning in Go" (https://talks.golang.org/2011/lex.slide, https://youtu.be/HxaD_trXwRE), which in turn was a presentation of an early version of Go's text/template parser. It follows, that this library borrows code from Go's standard library (BSD-style licensed).

The UCI grammar (for the purpose of this library) is defined as follows:

uci
		packageDecl*
		configDecl*

packageDecl
		`package` value CRLF configDecl*

configDecl
		`config` ident value? CRLF optionDecl*

optionDecl
		`option` ident value
		`list` ident value

ident
		[_a-zA-Z0-9]+

value
		`'` STRING `'`
		`"` STRING `"`
		ident

For now, UCI imports/exports (packageDecl production) are not supported yet. The STRING token (value production) is also somewhat vaguely defined, and needs to be aligned with the actual C implementation.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func AddSection

func AddSection(config, section, typ string) error

AddSection delegates to the default tree. See Tree for details.

func Commit

func Commit() error

Commit delegates to the default tree. See Tree for details.

func Del

func Del(config, section, option string)

Del delegates to the default tree. See Tree for details.

func DelSection

func DelSection(config, section string)

DelSection delegates to the default tree. See Tree for details.

func Get

func Get(config, section, option string) ([]string, bool)

Get delegates to the default tree. See Tree for details.

func IsConfigAlreadyLoaded

func IsConfigAlreadyLoaded(err error) bool

IsConfigAlreadyLoaded reports, whether err is of type ErrConfigAlredyLoaded.

func IsSectionTypeMismatch

func IsSectionTypeMismatch(err error) bool

IsSectionTypeMismatch reports, whether err is of type ErrSectionTypeMismatch.

func LoadConfig

func LoadConfig(name string, forceReload bool) error

LoadConfig delegates to the default tree. See Tree for details.

func Revert

func Revert(configs ...string)

Revert delegates to the default tree. See Tree for details.

func Set

func Set(config, section, option string, values ...string) bool

Set delegates to the default tree. See Tree for details.

Types

type ErrConfigAlreadyLoaded

type ErrConfigAlreadyLoaded struct {
	Name string
}

ErrConfigAlreadyLoaded is returned by LoadConfig, if the given config name is already present.

func (ErrConfigAlreadyLoaded) Error

func (err ErrConfigAlreadyLoaded) Error() string

type ErrSectionTypeMismatch

type ErrSectionTypeMismatch struct {
	Config, Section string // name
	ExistingType    string
	NewType         string
}

ErrSectionTypeMismatch is returned by AddSection if the section-to-add already exists with a different type.

func (ErrSectionTypeMismatch) Error

func (err ErrSectionTypeMismatch) Error() string

type Tree

type Tree interface {
	// LoadConfig reads a config file into memory and returns nil. If the
	// config is already loaded, and forceReload is false, an error of type
	// ErrConfigAlreadyLoaded is returned. Errors reading the config file
	// are returned verbatim.
	//
	// You don't need to explicitly call LoadConfig(): Accessing configs
	// (and their sections) via Get, Set, Add, Delete, DeleteAll will
	// load missing files automatically.
	LoadConfig(name string, forceReload bool) error

	// Commit writes all changes back to the system.
	//
	// Note: this is not transaction safe. If, for whatever reason, the
	// writing of any file fails, the succeeding files are left untouched
	// while the preceeding files are not reverted.
	Commit() error

	// Revert undoes changes to the config files given as arguments. If
	// no argument is given, all changes are reverted. This clears the
	// internal memory and does not access the file system.
	Revert(configs ...string)

	// GetSections returns the names of all sections of a certain type
	// in a config, and a boolean indicating whether the config file exists.
	GetSections(config string, secType string) ([]string, bool)

	// Get retrieves (all) values for a fully qualified option, and a
	// boolean indicating whether the config file and the config section
	// within exists.
	Get(config, section, option string) ([]string, bool)

	// Set replaces the fully qualified option with the given values. It
	// returns whether the config file and section exists. For new files
	// and sections, you first need to initialize them with AddSection().
	Set(config, section, option string, values ...string) bool

	// Del removes a fully qualified option.
	Del(config, section, option string)

	// AddSection adds a new config section. If the section already exists,
	// and the types match (existing type and given type), nothing happens.
	// Otherwise an ErrSectionTypeMismatch is returned.
	AddSection(config, section, typ string) error

	// DelSection remove a config section and its options.
	DelSection(config, section string)
}

Tree defines the base directory for UCI config files. The default value on OpenWRT devices point to /etc/config, so that is what the default tree uses as well (you can access the default tree with the package level functions with the same signature as in this interface).

func NewTree

func NewTree(root string) Tree

NewTree constructs new RootDir pointing to root.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL