gab

package module
v0.0.0-...-8585bba Latest Latest
Warning

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

Go to latest
Published: Nov 1, 2019 License: Apache-2.0 Imports: 5 Imported by: 0

README

gab

Gab is the Grub Auto Bootloader. Gab is used in order to reduce the complexity of bootloading from a kexec'ing host. With gab, the kexecer kexec's into grub with predefined settings such that the kexec'ing host does not need to have a copy of initramfs or the kernel in memory.

Gab is a gRPC service. A user sends a request to gab with:

	&gab.RRequest{
		Kernel:    "/boot/vmlinuz-4.15.0-42-generic",
		Initramfs: "/boot/initrd.img-4.15.0-29-generic",
		Uuid:      "ef0d7100-f746-11e8-96dc-525400123456",
		Label:     "",
		Kparams:   "ro maybe-ubiquity",
	})

These values can be extract from image builders such as packer to streamline the process. Kexec takes three items: a kernel (to load into memory), an optional initramfs for the kernel, and kernel parameters. Gab focuses mainly on the grub portion of bootloading an operating system. Gab will generate a kexec'able image with a grub configuration file baked in. Grub requires a Kernel as well, and takes in additional optional values such as the root disk location, and initramfs. With Gab, kexec does not need to extract a kernel and initramfs or /proc/cmdline from a disk. All that is needed are the paths relative to the root filesystem.

Gab returns a binary blob that should be written back to disk:

	resp, err := gabd.Request(ctx,
		&gab.RRequest{
			Kernel:    "/boot/vmlinuz-4.15.0-42-generic",
			Initramfs: "/boot/initrd.img-4.15.0-29-generic",
			Uuid:      "ef0d7100-f746-11e8-96dc-525400123456",
			Label:     "",
			Kparams:   "ro maybe-ubiquity",
		})

	...

	f, err := os.Create("grub.img")

	...

	f.Write(resp.Grub)

Which can then be used to kexec into:

qemu-system-x86_64 -kernel grub.img -hda ubuntu.qcow2 -m 1G

In conjunction with other mergetb services such as sled, gab can be used to bootload practically any operating system from u-root to provide a minimal bootload time - bypassing many minutes of server uefi firmware checks.

Building gab

I've tried to make building gab as easy as possible- there are likely some rough edges, I welcome any comments and/or PR requests!

Both the container and the software need to have some notion of the target architecture that grub is being developed for. Gab uses grub-mkstandalone to build the grub image, and uses the -d option to specify the directory where the grub modules are loaded. For gab this is done through the get_bins.sh script. This script takes in as an argument grub's --target argument. Currently we have configured and built to two targets: i386-pc, which allows us to test our virtual configuration with qemu, and x86_64-efi, which is the target for one of the boards we are developing on. The get_bins script will query https://build.mergetb.net/gab/grub-core-$cpu.tar.gz for the $cpu variable passed in. This is the pre-compiled modules grub-core that grub-mkstandalone will use to source the modules.

The gab.dock dockerfile illistrates this:

	# get & extract all modules for grub-mkstandalone
	COPY ./get_bins.sh ./
	RUN ./get_bins.sh $ARCHSUPPORT

	CMD /usr/bin/gabd -iface 0.0.0.0 -port 9913 -arch $ARCHSUPPORT

So in using the containers, a user-specified $ARCHSUPPORT is used to pass in which target environment gab should cater to. As for the CMD line, $ARCHSUPPORT is used to specify specific modules due to the target. For example, biosdisk is a module that exists on i386-pc, but not on x86_64-efi. We can also not include all modules as in the case of i386-pc because the grub binary that grub-mkstandalone generates, is too large.

So with that disclaimer out of the way, to actually build the code. The first step is to download the grub-core (or build yourself) for your target platform.

I'll use values for testing on qemu:

	./get_bins.sh i386-pc

Next, we can build the code (make will call golang's dep):

	make

Now we have a gab binary in build/gabd, we can test locally on our machine by using the test script in tests/ (you will need to change the hostname for gab as this is configured for docker containers).

	./build/gabd -iface 0.0.0.0 -port 9913 -arch i386-pc &
	go test -v tests/

The result should be a binary in tests/build called test.bin that we can now load through qemu:

	qemu-system-x86_64 -kernel grub.img -hda ubuntu.qcow2 -m 1G

A few points to note at this point:

  1. You will need to create an ubuntu disk image (and install ubuntu onto it). I have not yet done this process via packer to simplify everything.
qemu-img create -f qcow2  ubuntu.qcow2 32G
sudo qemu-system-x86_64 -enable-kvm -cpu host -hda ubuntu.qcow2 -boot d -cdrom ubuntu-18.04.1-live-server-amd64.iso -m 2G
  1. Once the OS is ready, you will need to extract the Kernel and Initrfamfs paths, as well as the rootfs's uuid or label.

To build the docker container you can use the provided:

	./build-container.sh

Tests can then be done through docker compose to verify gab communication:

    - ARCHSUPPORT=i386-pc docker-compose build --no-cache
    - ARCHSUPPORT=i386-pc docker-compose up --force-recreate &
    - docker-compose run test go test -v /go/src/gitlab.com/mergetb/tech/gab/tests/

Contributing

Please open an issue and/or contribute a PR request. Thank you!

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func RegisterGabServer

func RegisterGabServer(s *grpc.Server, srv GabServer)

Types

type GabClient

type GabClient interface {
	Request(ctx context.Context, in *RRequest, opts ...grpc.CallOption) (*RequestResponse, error)
}

GabClient is the client API for Gab service.

For semantics around ctx use and closing/ending streaming RPCs, please refer to https://godoc.org/google.golang.org/grpc#ClientConn.NewStream.

func NewGabClient

func NewGabClient(cc *grpc.ClientConn) GabClient

type GabServer

type GabServer interface {
	Request(context.Context, *RRequest) (*RequestResponse, error)
}

GabServer is the server API for Gab service.

type RRequest

type RRequest struct {
	Kernel               string   `protobuf:"bytes,1,opt,name=kernel,proto3" json:"kernel,omitempty"`
	Initramfs            string   `protobuf:"bytes,2,opt,name=initramfs,proto3" json:"initramfs,omitempty"`
	Uuid                 string   `protobuf:"bytes,3,opt,name=uuid,proto3" json:"uuid,omitempty"`
	Label                string   `protobuf:"bytes,4,opt,name=label,proto3" json:"label,omitempty"`
	Kparams              string   `protobuf:"bytes,5,opt,name=kparams,proto3" json:"kparams,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (*RRequest) Descriptor

func (*RRequest) Descriptor() ([]byte, []int)

func (*RRequest) GetInitramfs

func (m *RRequest) GetInitramfs() string

func (*RRequest) GetKernel

func (m *RRequest) GetKernel() string

func (*RRequest) GetKparams

func (m *RRequest) GetKparams() string

func (*RRequest) GetLabel

func (m *RRequest) GetLabel() string

func (*RRequest) GetUuid

func (m *RRequest) GetUuid() string

func (*RRequest) ProtoMessage

func (*RRequest) ProtoMessage()

func (*RRequest) Reset

func (m *RRequest) Reset()

func (*RRequest) String

func (m *RRequest) String() string

func (*RRequest) XXX_DiscardUnknown

func (m *RRequest) XXX_DiscardUnknown()

func (*RRequest) XXX_Marshal

func (m *RRequest) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)

func (*RRequest) XXX_Merge

func (dst *RRequest) XXX_Merge(src proto.Message)

func (*RRequest) XXX_Size

func (m *RRequest) XXX_Size() int

func (*RRequest) XXX_Unmarshal

func (m *RRequest) XXX_Unmarshal(b []byte) error

type RequestResponse

type RequestResponse struct {
	Grub                 []byte   `protobuf:"bytes,1,opt,name=grub,proto3" json:"grub,omitempty"`
	XXX_NoUnkeyedLiteral struct{} `json:"-"`
	XXX_unrecognized     []byte   `json:"-"`
	XXX_sizecache        int32    `json:"-"`
}

func (*RequestResponse) Descriptor

func (*RequestResponse) Descriptor() ([]byte, []int)

func (*RequestResponse) GetGrub

func (m *RequestResponse) GetGrub() []byte

func (*RequestResponse) ProtoMessage

func (*RequestResponse) ProtoMessage()

func (*RequestResponse) Reset

func (m *RequestResponse) Reset()

func (*RequestResponse) String

func (m *RequestResponse) String() string

func (*RequestResponse) XXX_DiscardUnknown

func (m *RequestResponse) XXX_DiscardUnknown()

func (*RequestResponse) XXX_Marshal

func (m *RequestResponse) XXX_Marshal(b []byte, deterministic bool) ([]byte, error)

func (*RequestResponse) XXX_Merge

func (dst *RequestResponse) XXX_Merge(src proto.Message)

func (*RequestResponse) XXX_Size

func (m *RequestResponse) XXX_Size() int

func (*RequestResponse) XXX_Unmarshal

func (m *RequestResponse) XXX_Unmarshal(b []byte) error

Directories

Path Synopsis

Jump to

Keyboard shortcuts

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