pixiecore

package
v0.3.2 Latest Latest
Warning

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

Go to latest
Published: Feb 13, 2024 License: Apache-2.0 Imports: 35 Imported by: 1

README

Pixiecore

Pixiecore is an tool to manage network booting of machines. It can be used for simple single shot network boots, or as a building block of machine management infrastructure.

license api cli cli

TL;DR

pixiecore quick xyz --dhcp-no-bind

Then try to boot another machine from the same network.

Why?

Booting a Linux system over the network is quite tedious. You have to set up a TFTP server, reconfigure your DHCP server to recognize PXE clients, and send them the right set of magical options to get them to boot, often fighting rubbish PXE ROM implementations.

Pixiecore aims to simplify this process, by packing the whole process into a single binary that can cooperate with your network's existing DHCP server. You don't need to reconfigure anything else in the network.

If you're curious about the whole process that Pixiecore manages, you can read the details in README.booting.

Installation

Pixiecore is available in a variety of forms. All of them automatically track this repository, so you always get the latest build.

Go get

Build the latest Pixiecore via go get:

go get github.com/metal-stack/cmd/pixiecore
Debian/Ubuntu

A Debian/Ubuntu package is available from packagecloud.io. They have extensive configuration instructions for a variety of mechanisms, but the quick version is:

sudo apt-get install -y apt-transport-https
curl -L https://packagecloud.io/danderson/pixiecore/gpgkey | sudo apt-key add -
echo "deb https://packagecloud.io/danderson/pixiecore/debian stretch main" >/etc/apt/sources.list.d/pixiecore.list
sudo apt-get update
sudo apt-get install pixiecore

Note that you should reference debian/stretch regardless of your actual distro. The pixiecore binary is built statically and should work fine on all distros, so we only build one variant of the package. Please file a bug if you hit problems with this setup.

Container images

Docker and ACI autobuilds are available. They track the latest code from this repository.

Using Pixiecore in static mode ("I just want to boot a machine")

Run the pixiecore binary, passing it a kernel and initrd, and optionally some extra kernel commandline arguments. For example, here's how you make all machines in your network netboot into the alpha release of CoreOS, with automatic login:

sudo pixiecore boot \
  https://alpha.release.core-os.net/amd64-usr/current/coreos_production_pxe.vmlinuz \
  https://alpha.release.core-os.net/amd64-usr/current/coreos_production_pxe_image.cpio.gz \
  --cmdline='coreos.autologin'

That's it! Any machine that tries to boot from the network will now boot into CoreOS.

That's a bit slow to boot, because Pixiecore is refetching the images from core-os.net each time a machine tries to boot. We can also download the files and use those:

wget https://alpha.release.core-os.net/amd64-usr/current/coreos_production_pxe.vmlinuz
wget https://alpha.release.core-os.net/amd64-usr/current/coreos_production_pxe_image.cpio.gz
sudo pixiecore boot \
  coreos_production_pxe.vmlinuz \
  coreos_production_pxe_image.cpio.gz \
  --cmdline='coreos.autologin'

Sometimes, you want to give extra files to the booting OS. For example, CoreOS lets you pass a Cloud Init file via the cloud-config-url kernel commandline parameter. That's fine if you have a URL, but what if you have a local file?

For this, Pixiecore lets you specify that you want an additional file served over HTTP to the booting OS, via a template function. Let's grab a cloud-config.yml that sets the hostname to pixiecore-test, and serve it:

wget -O my-cloud-config.yml https://goo.gl/7HzZf2
sudo pixiecore boot \
  coreos_production_pxe.vmlinuz \
  coreos_production_pxe_image.cpio.gz \
  --cmdline='coreos.autologin cloud-config-url={{ ID "./my-cloud-config.yml" }}'

Pixiecore will transform the template invocation into a URL that, when fetched, serves my-cloud-config.yml. Similarly to the kernel and initrd arguments, you can also pass a URL to the ID template function.

Pixiecore in API mode

Think of Pixiecore in API mode as a "PXE to HTTP" translator. Whenever Pixiecore sees a machine trying to netboot, it will ask a remote HTTP API (which you implement) what to do. The API server can tell Pixiecore to ignore the machine, or tell it to boot into a given kernel/initrd/commandline.

Effectively, Pixiecore in API mode lets you pretend that your machines speak a simple JSON protocol when trying to netboot. This makes it far easier to play with netbooting in your own software.

To start Pixiecore in API mode, pass it the URL of your API endpoint:

sudo pixiecore api https://foo.example/pixiecore

The endpoint you provide must implement the Pixiecore boot API, as described in the API spec.

You can find a sample API server implementation in the api-example subdirectory. The code is not production-grade, but gives a short illustration of how the protocol works by reimplementing a subset of Pixiecore's static mode as an API server.

Running in containers

Pixiecore is available both as an ACI image for rkt, and as a Docker image for Docker Engine. Both images are automatically built whenever the github repository changes.

Because Pixiecore needs to listen for DHCP traffic, it has to run with access to the host's networking stack. Both Rkt and Docker do this with the --net=host commandline flag.

sudo rkt run --net=host \
  --volume images,kind=host,source=/var/images \
  --mount volume=images,target=/image \
  quay.io/pixiecore/pixiecore -- \
    boot /image/coreos_production_pxe.vmlinuz /image/coreos_production_pxe_image.cpio.gz

sudo docker run \
  --net=host \
  -v .:/image \
  danderson/pixiecore \
    boot /image/coreos_production_pxe.vmlinuz /image/coreos_production_pxe_image.cpio.gz

Demos and users

Pixiecore was used alongside waitron in a presentation at the OpenStack summit in 2016.

If you use Pixiecore, we'd love to hear about it, and know more about how you're using it. You can open a pull request to be added to this list, file an issue for me to add you, or just email me at dave(at)natulte.net if you'd like to give feedback privately.

  • waitron uses Pixiecore to manage automated server installation based on machine templates.

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type APIBootConfiguration

type APIBootConfiguration struct {
	Client        *http.Client
	URLPrefix     string
	RecursiveDNS  []net.IP
	Preference    []byte
	UsePreference bool
}

APIBootConfiguration provides an interface to retrieve Boot File URL from an external server based on client ID and architecture type

func MakeAPIBootConfiguration

func MakeAPIBootConfiguration(url string, timeout time.Duration, preference uint8, usePreference bool,
	dnsServerAddresses []net.IP) *APIBootConfiguration

MakeAPIBootConfiguration creates a new APIBootConfiguration initialized with provided values

func (*APIBootConfiguration) GetBootURL

func (bc *APIBootConfiguration) GetBootURL(id []byte, clientArchType uint16) ([]byte, error)

GetBootURL returns Boot File URL, see RFC 5970

func (*APIBootConfiguration) GetPreference

func (bc *APIBootConfiguration) GetPreference() []byte

GetPreference returns server's Preference, see RFC 3315

func (*APIBootConfiguration) GetRecursiveDNS

func (bc *APIBootConfiguration) GetRecursiveDNS() []net.IP

GetRecursiveDNS returns list of addresses of recursive DNS servers, see RFC 3646

type Architecture

type Architecture int

Architecture describes a kind of CPU architecture.

const (
	// ArchIA32 is a 32-bit x86 machine. It _may_ also support X64
	// execution, but Pixiecore has no way of knowing.
	ArchIA32 Architecture = iota
	// ArchX64 is a 64-bit x86 machine (aka amd64 aka X64).
	ArchX64
)

Architecture types that Pixiecore knows how to boot.

These architectures are self-reported by the booting machine. The machine may support additional execution modes. For example, legacy PC BIOS reports itself as an ArchIA32, but may also support ArchX64 execution.

func (Architecture) String

func (a Architecture) String() string

type Booter

type Booter interface {
	// The given MAC address wants to know what it should
	// boot. What should Pixiecore make it boot?
	//
	// Returning an error or a nil BootSpec will make Pixiecore ignore
	// the client machine's request.
	BootSpec(m Machine) (*Spec, error)
	// Get the bytes corresponding to an ID given in Spec.
	//
	// Additionally returns the total number of bytes in the
	// ReadCloser, or -1 if the size is unknown. Be warned, returning
	// -1 will make the boot process orders of magnitude slower due to
	// poor ipxe behavior.
	ReadBootFile(id ID) (io.ReadCloser, int64, error)
	// Write the given Reader to an ID given in Spec.
	WriteBootFile(id ID, body io.Reader) error
}

A Booter provides boot instructions and files for machines.

Due to the stateless nature of various boot protocols, BootSpec() will be called multiple times in the course of a single boot attempt.

func APIBooter

func APIBooter(url string, timeout time.Duration) (Booter, error)

APIBooter gets a BootSpec from a remote server over HTTP.

The API is described in README.api.md

func GRPCBooter added in v0.2.0

func GRPCBooter(log *slog.Logger, client *GrpcClient, partition string, metalAPIConfig *api.MetalConfig) (Booter, error)

type Firmware

type Firmware int

Firmware describes a kind of firmware attempting to boot.

This should only be used for selecting the right bootloader within Pixiecore, kernel selection should key off the more generic Architecture.

const (
	FirmwareX86PC         Firmware = iota // "Classic" x86 BIOS with PXE/UNDI support
	FirmwareEFI32                         // 32-bit x86 processor running EFI
	FirmwareEFI64                         // 64-bit x86 processor running EFI
	FirmwareEFIBC                         // 64-bit x86 processor running EFI
	FirmwareX86Ipxe                       // "Classic" x86 BIOS running iPXE (no UNDI support)
	FirmwarePixiecoreIpxe                 // Pixiecore's iPXE, which has replaced the underlying firmware
)

The bootloaders that Pixiecore knows how to handle.

type GrpcClient added in v0.2.0

type GrpcClient struct {
	// contains filtered or unexported fields
}

func NewGrpcClient added in v0.2.0

func NewGrpcClient(log *slog.Logger, config *api.MetalConfig) (*GrpcClient, error)

NewGrpcClient fetches the address and certificates from metal-core needed to communicate with metal-api via grpc, and returns a new grpc client that can be used to invoke all provided grpc endpoints.

func (*GrpcClient) BootService added in v0.2.0

func (c *GrpcClient) BootService() v1.BootServiceClient

type ID

type ID string

An ID is an identifier used by Booters to reference files.

type Machine

type Machine struct {
	MAC  net.HardwareAddr
	Arch Architecture
	GUID string
}

A Machine describes a machine that is attempting to boot.

type Server

type Server struct {
	Booter Booter

	// Address to listen on, or empty for all interfaces.
	Address string
	// HTTP port for boot services.
	HTTPPort int
	// HTTP port for human-readable information. Can be the same as
	// HTTPPort.
	HTTPStatusPort int

	// MetricsPort is the port of the metrics server.
	MetricsPort int
	// MetricsAddress is the bind address that the metrics server listens on.
	MetricsAddress string

	// Ipxe lists the supported bootable Firmwares, and their
	// associated ipxe binary.
	Ipxe map[Firmware][]byte

	// Log receives logs on Pixiecore's operation. If nil, logging
	// is suppressed.
	Log *slog.Logger

	// These ports can technically be set for testing, but the
	// protocols burned in firmware on the client side hardcode these,
	// so if you change them in production, nothing will work.
	DHCPPort int
	TFTPPort int
	PXEPort  int

	// Listen for DHCP traffic without binding to the DHCP port. This
	// enables coexistence of Pixiecore with another DHCP server.
	//
	// Currently only supported on Linux.
	DHCPNoBind bool

	MetalConfig *api.MetalConfig
	// contains filtered or unexported fields
}

A Server boots machines using a Booter.

func (*Server) Serve

func (s *Server) Serve() error

Serve listens for machines attempting to boot, and uses Booter to help them.

func (*Server) Shutdown

func (s *Server) Shutdown()

Shutdown causes Serve() to exit, cleaning up behind itself.

type ServerV6

type ServerV6 struct {
	Address string
	Port    string
	Duid    []byte

	BootConfig    dhcp6.BootConfiguration
	PacketBuilder *dhcp6.PacketBuilder
	AddressPool   dhcp6.AddressPool

	Log *slog.Logger
	// contains filtered or unexported fields
}

ServerV6 boots machines using a Booter.

func NewServerV6

func NewServerV6() *ServerV6

NewServerV6 returns a new ServerV6.

func (*ServerV6) Serve

func (s *ServerV6) Serve() error

Serve listens for machines attempting to boot, and responds to their DHCPv6 requests.

func (*ServerV6) Shutdown

func (s *ServerV6) Shutdown()

Shutdown causes Serve() to exit, cleaning up behind itself.

type Spec

type Spec struct {
	// The kernel to boot
	Kernel ID
	// Optional init ramdisks for linux kernels
	Initrd []ID
	// Optional kernel commandline. This string is evaluated as a
	// text/template template, in which "ID(x)" function is
	// available. Invoking ID(x) returns a URL that will call
	// Booter.ReadBootFile(x) when fetched.
	Cmdline string
	// Message to print on the client machine before booting.
	Message string

	// A raw iPXE script to run. Overrides all of the above.
	//
	// THIS IS NOT A STABLE INTERFACE. This will only work for
	// machines that get booted via iPXE. Currently, that is all of
	// them, but there is no guarantee that this will remain
	// true. When passing a custom iPXE script, it is your
	// responsibility to make the boot succeed, Pixiecore's
	// involvement ends when it serves your script.
	IpxeScript string
}

A Spec describes a kernel and associated configuration.

type StaticBootConfiguration

type StaticBootConfiguration struct {
	HTTPBootURL   []byte
	IPxeBootURL   []byte
	RecursiveDNS  []net.IP
	Preference    []byte
	UsePreference bool
}

StaticBootConfiguration provides values for dhcp options that remain unchanged until restart

func MakeStaticBootConfiguration

func MakeStaticBootConfiguration(httpBootURL, ipxeBootURL string, preference uint8, usePreference bool,
	dnsServerAddresses []net.IP) *StaticBootConfiguration

MakeStaticBootConfiguration creates a new StaticBootConfiguration with provided values

func (*StaticBootConfiguration) GetBootURL

func (bc *StaticBootConfiguration) GetBootURL(id []byte, clientArchType uint16) ([]byte, error)

GetBootURL returns Boot File URL, see RFC 5970

func (*StaticBootConfiguration) GetPreference

func (bc *StaticBootConfiguration) GetPreference() []byte

GetPreference returns server's Preference, see RFC 3315

func (*StaticBootConfiguration) GetRecursiveDNS

func (bc *StaticBootConfiguration) GetRecursiveDNS() []net.IP

GetRecursiveDNS returns list of addresses of recursive DNS servers, see RFC 3646

Directories

Path Synopsis
Package cli implements the commandline interface for Pixiecore.
Package cli implements the commandline interface for Pixiecore.

Jump to

Keyboard shortcuts

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