narcissus

package module
v0.0.0-...-28d46c8 Latest Latest
Warning

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

Go to latest
Published: May 24, 2020 License: Apache-2.0 Imports: 6 Imported by: 1

README

Narcissus: edit configuration files as go structs

Documentation Build Status Coverage Status Go Report Card

This go package aims to provide reflection for the Augeas library.

This allows to turn Augeas lenses into Go structs for easy parsing and modification of configuration files.

Example

import (
	"log"

	"honnef.co/go/augeas"
	"github.com/raphink/narcissus"
)

func main() {
	aug, err := augeas.New("/", "", augeas.None)
	if err != nil {
		log.Fatal("Failed to create Augeas handler")
	}
	n := narcissus.New(&aug)

	user := n.NewPasswdUser("raphink")
	if err != nil {
		log.Fatalf("Failed to retrieve user: %v" err)
	}

	log.Printf("UID=%v", user.UID)

	// Modify UID
	user.UID = 42
  
	err = n.Write(user)
	if err != nil {
		log.Fatalf("Failed to save user: %v", err)
	}
}

Available types

Fstab
  • Fstab maps a whole /etc/fstab file
  • FstabEntry maps a single /etc/fstab entry
Hosts
  • Hosts maps a whole /etc/hosts file
  • Host maps a single /etc/hosts entry
Passwd
  • Passwd maps a whole /etc/passwd file
  • PasswdUser maps a single /etc/passwd entry
Services
  • Services maps a whole /etc/services file
  • Service maps a single /etc/services entry

Mapping your own structures

import (
	"log"

	"honnef.co/go/augeas"
	"github.com/raphink/narcissus"
)

type group struct {
	augeasPath string
	Name       string   `narcissus:".,value-from-label"`
	Password   string   `narcissus:"password"`
	GID        int      `narcissus:"gid"`
	Users      []string `narcissus:"user"`
}


func main() {
	aug, err := augeas.New("/", "", augeas.None)
	if err != nil {
		log.Fatal("Failed to create Augeas handler")
	}
	n := narcissus.New(&aug)

	group := &group{
		augeasPath: "/files/etc/group/docker",
	}
	err = n.Parse(group)
	if err != nil {
		log.Fatalf("Failed to retrieve group: %v", err)
	}

	log.Printf("GID=%v", group.GID)
	log.Printf("Users=%v", strings.Join(group.Users, ","))
}

Tag values

The narcissus tag accepts multiple comma separated values. The first value in the list is the relative path where the field is mapped in the Augeas tree.

Other possible (optional) values are:

  • value-from-label: get field value from the node label instead of its value;
  • seq (slice field only): will treat field as a seq entry in the Augeas tree;
  • key-from-value (map field only): get the key from the node label instead of its value;
  • purge (map field only): purge all unknown keys in the map.

Fields

Described structures have special fields to specify parameters for Augeas.

  • augeasPath (mandatory): the path to the structure in the Augeas tree;
  • augeasFile (optional): let Augeas load only this file. If augeasLens is not specified, Augeas will use the default lens for the file if available;
  • augeasLens (optional): if augeasFile is set (ignored otherwise), specifies which lens to use to parse the file. This is required when parsing a file at a non-standard location.

Each of these fields can be specified in one of two ways:

  • by using the default tag with a default value for the field, e.g.
type group struct {
	augeasPath string `default:"/files/etc/group/root"`
}
  • by specifying a value for the instance in the structure field, e.g.
myGroup := group {
    augeasPath: "/files/etc/group/docker",
}

Documentation

Index

Examples

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type Fstab

type Fstab struct {
	Comments []struct {
		Comment string `narcissus:"."`
	} `narcissus:"#comment"`
	Entries []FstabEntry `narcissus:"seq"`
	// contains filtered or unexported fields
}

Fstab maps a /etc/fstab file

type FstabEntry

type FstabEntry struct {
	Spec    string              `narcissus:"spec"`
	File    string              `narcissus:"file"`
	Vfstype string              `narcissus:"vfstype"`
	Opt     map[string]FstabOpt `narcissus:"opt"`
	Dump    int                 `narcissus:"dump"`
	Passno  int                 `narcissus:"passno"`
	// contains filtered or unexported fields
}

FstabEntry maps an Fstab entry

type FstabOpt

type FstabOpt struct {
	Value string `narcissus:"value"`
}

FstabOpt is an FstabEntry opt

type Host

type Host struct {
	IPAddress string   `narcissus:"ipaddr"`
	Canonical string   `narcissus:"canonical"`
	Aliases   []string `narcissus:"alias"`
	Comment   string   `narcissus:"#comment"`
	// contains filtered or unexported fields
}

Host maps an Hosts entry

type Hosts

type Hosts struct {
	Comments []struct {
		Comment string `narcissus:"."`
	} `narcissus:"#comment"`
	Hosts []Host `narcissus:"seq"`
	// contains filtered or unexported fields
}

Hosts maps a /etc/hosts file

type Narcissus

type Narcissus struct {
	Augeas *augeas.Augeas
}

Narcissus is a Narcissus handler

func New

func New(aug *augeas.Augeas) *Narcissus

New returns a new Narcissus handler with given Augeas handler

func (*Narcissus) Autoload

func (n *Narcissus) Autoload(ref reflect.Value) (err error)

func (*Narcissus) NewFstab

func (n *Narcissus) NewFstab() (f *Fstab, err error)

NewFstab returns a new Fstab structure

Example
aug, err := augeas.New(fakeroot, "", augeas.None)
if err != nil {
	log.Fatal("Failed to create Augeas handler")
}
n := New(&aug)

fstab, err := n.NewFstab()
if err != nil {
	log.Fatalf("Expected no error, got %v", err)
}

fmt.Printf("File=%v", fstab.Entries[0].File)
Output:

File=/

func (*Narcissus) NewHosts

func (n *Narcissus) NewHosts() (h *Hosts, err error)

NewHosts returns a new Hosts structure

Example
aug, err := augeas.New(fakeroot, "", augeas.None)
if err != nil {
	log.Fatal("Failed to create Augeas handler")
}
n := New(&aug)

hosts, err := n.NewHosts()
if err != nil {
	log.Fatalf("Expected no error, got %v", err)
}

fmt.Printf("IP=%v", hosts.Hosts[0].IPAddress)
Output:

IP=127.0.0.1

func (*Narcissus) NewPasswd

func (n *Narcissus) NewPasswd() (p *Passwd, err error)

NewPasswd returns a new Passwd structure

Example
aug, err := augeas.New("/", "", augeas.None)
if err != nil {
	log.Fatal("Failed to create Augeas handler")
}
n := New(&aug)

passwd, err := n.NewPasswd()
if err != nil {
	log.Fatalf("Failed to parse passwd: %v", err)
}

fmt.Printf("UID=%v", passwd.Users["root"].UID)
Output:

UID=0

func (*Narcissus) NewPasswdUser

func (n *Narcissus) NewPasswdUser(user string) (p *PasswdUser, err error)

NewPasswdUser returns a new PasswdUser structure for given user

Example
aug, err := augeas.New("/", "", augeas.None)
if err != nil {
	log.Fatal("Failed to create Augeas handler")
}
n := New(&aug)

user, err := n.NewPasswdUser("root")
if err != nil {
	log.Fatalf("Failed to parse user: %v", err)
}

fmt.Printf("UID=%v", user.UID)
Output:

UID=0
Example (Write)
aug, err := augeas.New(fakeroot, "", augeas.SaveNewFile)
if err != nil {
	log.Fatal("Failed to create Augeas handler")
}
n := New(&aug)

passwd, err := n.NewPasswd()
if err != nil {
	log.Fatalf("Failed to parse passwd: %v", err)
}

// Retrieves user if exists, empty user otherwise
user, err := n.NewPasswdUser("foo")
user.UID = 314
user.GID = 314
user.Name = "Foo Bar"
user.Home = "/home/foo"
user.Shell = "/bin/sh"
user.Password = "XXX"
passwd.Users["foo"] = *user

err = n.Write(passwd)
if err != nil {
	log.Fatalf("Failed to write passwd: %v", err)
}

fmt.Printf("UID=%v", passwd.Users["foo"].UID)
Output:

UID=314

func (*Narcissus) NewService

func (n *Narcissus) NewService(name string, protocol string) (s *Service, err error)

NewService returns a new Service structure

Example
aug, err := augeas.New("/", "", augeas.None)
if err != nil {
	log.Fatal("Failed to create Augeas handler")
}
n := New(&aug)

service, err := n.NewService("ssh", "tcp")
if err != nil {
	log.Fatalf("Expected no error, got %v", err)
}

fmt.Printf("Port=%v", service.Port)
Output:

Port=22

func (*Narcissus) NewServices

func (n *Narcissus) NewServices() (s *Services, err error)

NewServices returns a new Services structure

Example
aug, err := augeas.New("/", "", augeas.None)
if err != nil {
	log.Fatal("Failed to create Augeas handler")
}
n := New(&aug)

services, err := n.NewServices()
if err != nil {
	log.Fatalf("Expected no error, got %v", err)
}

fmt.Printf("Port=%v", services.Services[0].Port)
Output:

Port=1

func (*Narcissus) Parse

func (n *Narcissus) Parse(val interface{}) error

Parse parses a structure pointer and feeds its fields with Augeas data

Example
type group struct {
	augeasPath string
	Name       string   `path:"." value-from:"label"`
	Password   string   `path:"password"`
	GID        int      `path:"gid"`
	Users      []string `path:"user"`
}

aug, err := augeas.New("/", "", augeas.None)
if err != nil {
	log.Fatal("Failed to create Augeas handler")
}
n := New(&aug)

g := &group{
	augeasPath: "/files/etc/group/adm",
}
err = n.Parse(g)
if err != nil {
	log.Fatalf("Expected no error, got %v", err)
}

fmt.Printf("GID=%v", g.GID)
Output:

GID=4

func (*Narcissus) Write

func (n *Narcissus) Write(val interface{}) error

Write writes a structure pointer to the Augeas tree

Example
aug, err := augeas.New(fakeroot, "", augeas.SaveNewFile)
if err != nil {
	log.Fatal("Failed to create Augeas handler")
}
n := New(&aug)

passwd, err := n.NewPasswd()
err = n.Parse(passwd)
if err != nil {
	log.Fatalf("Failed to parse passwd: %v", err)
}

user := passwd.Users["root"]
fmt.Printf("Shell=%v\n", user.Shell)

user.Shell = "/bin/zsh"
passwd.Users["root"] = user

err = n.Write(passwd)
if err != nil {
	log.Fatalf("Failed to write passwd: %v", err)
}

cmd := exec.Command("grep", "^root", fakeroot+"/etc/passwd.augnew")
var out bytes.Buffer
cmd.Stdout = &out
err = cmd.Run()
if err != nil {
	log.Fatalf("Failed to run grep: %v", err)
}

fmt.Println(out.String())
Output:

Shell=/bin/bash
root:x:0:0:root:/root:/bin/zsh

type Passwd

type Passwd struct {
	Users map[string]PasswdUser `narcissus:"*,key-from-label"`
	// contains filtered or unexported fields
}

Passwd maps /etc/passwd

type PasswdUser

type PasswdUser struct {
	Account  string `narcissus:".,value-from-label"`
	Password string `narcissus:"password"`
	UID      int    `narcissus:"uid"`
	GID      int    `narcissus:"gid"`
	Name     string `narcissus:"name"`
	Home     string `narcissus:"home"`
	Shell    string `narcissus:"shell"`
	// contains filtered or unexported fields
}

PasswdUser maps a Passwd user

type Service

type Service struct {
	Name     string `narcissus:"."`
	Port     int    `narcissus:"port"`
	Protocol string `narcissus:"protocol"`
	Comment  string `narcissus:"#comment"`
	// contains filtered or unexported fields
}

Service maps a Services entry

type Services

type Services struct {
	Comments []struct {
		Comment string `narcissus:"."`
	} `narcissus:"#comment"`
	Services []Service `narcissus:"service-name"`
	// contains filtered or unexported fields
}

Services maps a /etc/services file

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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