Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Remote bravetools backend #254

Merged
merged 4 commits into from
Feb 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
79 changes: 46 additions & 33 deletions commands/init.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ var hostInit = &cobra.Command{
}

var hostConfigPath, storage, ram, network, backendType string
var remoteBackend bool

func init() {
includeInitFlags(hostInit)
Expand All @@ -31,6 +32,8 @@ func includeInitFlags(cmd *cobra.Command) {
cmd.PersistentFlags().StringVarP(&storage, "storage", "s", "12", "Host storage size in GB[OPTIONAL]. default: 12")
cmd.PersistentFlags().StringVarP(&ram, "memory", "m", "4GB", "Host memory size [OPTIONAL]. default 4GB")
cmd.PersistentFlags().StringVarP(&network, "network", "n", "", "Host network IP range [OPTIONAL]. default: randomly generate RFC1918 address")

cmd.PersistentFlags().BoolVar(&remoteBackend, "remote", false, "whether backend is remote (will not be initialized)")
}

func serverInit(cmd *cobra.Command, args []string) {
Expand All @@ -41,27 +44,32 @@ func serverInit(cmd *cobra.Command, args []string) {
}

hostOs := runtime.GOOS
switch hostOs {
case "linux":
backendType = "lxd"
case "darwin":
backendType = "multipass"
case "windows":
backendType = "multipass"
default:
err := deleteBraveHome(userHome)
if err != nil {
fmt.Println(err.Error())

if !remoteBackend {
switch hostOs {
case "linux":
backendType = "lxd"
case "darwin":
backendType = "multipass"
case "windows":
backendType = "multipass"
default:
err := deleteBraveHome(userHome)
if err != nil {
fmt.Println(err.Error())
}
log.Fatal("unsupported host OS: ", hostOs)
}
log.Fatal("unsupported host OS: ", hostOs)
}

if network == "" {
ip, err := shared.GenerateRandomRFC1919()
if err != nil {
log.Fatal(err.Error())
if network == "" {
ip, err := shared.GenerateRandomRFC1919()
if err != nil {
log.Fatal(err.Error())
}
network = ip
}
network = ip
} else {
backendType = "remote"
}

// Create $HOME/.bravetools
Expand All @@ -70,6 +78,21 @@ func serverInit(cmd *cobra.Command, args []string) {
log.Fatal(err.Error())
}

dbPath := path.Join(userHome, shared.BraveDB)

log.Println("Initialising Bravetools unit database")
_, err = os.Stat(dbPath)
if os.IsNotExist(err) {
err = db.InitDB(dbPath)

if err != nil {
if err := deleteBraveHome(userHome); err != nil {
fmt.Println(err.Error())
}
log.Fatal("failed to initialize database: ", err)
}
}

params := platform.HostConfig{
Storage: storage,
Ram: ram,
Expand All @@ -92,6 +115,11 @@ func serverInit(cmd *cobra.Command, args []string) {
loadConfig()
}

if remoteBackend {
fmt.Println("bravetools initialized - add a remote with `brave remote add local ...`")
return
}

log.Println("Initialising Bravetools backend")
err = backend.BraveBackendInit()
if err != nil {
Expand Down Expand Up @@ -148,19 +176,4 @@ func serverInit(cmd *cobra.Command, args []string) {
}
log.Fatal(err)
}

dbPath := path.Join(userHome, shared.BraveDB)

log.Println("Initialising Bravetools unit database")
_, err = os.Stat(dbPath)
if os.IsNotExist(err) {
err = db.InitDB(dbPath)

if err != nil {
if err := deleteBraveHome(userHome); err != nil {
fmt.Println(err.Error())
}
log.Fatal("failed to initialize database: ", err)
}
}
}
29 changes: 26 additions & 3 deletions docs/docs/init.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ description: "Bravetools initialisation."

# Introduction

Bravetools uses [LXD](https://documentation.ubuntu.com/lxd/en/latest/) to build, deploy, and manage System Containers. This means that on most Linux-like systems it can run natively, provided that LXD is installed. On MacOS/Windows, Bravetools uses a lightweight [Multipass VM](https://multipass.run) to take care of the Linux kernel features required by LXC containers.
Bravetools uses [LXD](https://documentation.ubuntu.com/lxd/en/latest/) to build, deploy, and manage System Containers. This means that on most Linux-like systems it can run natively, provided that LXD is installed. On MacOS/Windows, Bravetools uses a lightweight [Multipass VM](https://multipass.run) to take care of the Linux kernel features required by LXC containers. Alternatively, a [remote LXD instance can be set as a backend](#remote-backends).

Bravetools relies on the following LXD features:

Expand Down Expand Up @@ -61,10 +61,33 @@ status: inactive
remote: local
```

>> **Note** that on Linux machines, `backensettings` option is ignored.
>> **Note** that on Linux machines and remote backends, `backensettings` option is ignored.

A file-based configuration allows you to explicitly specify profile, storage, and network names, as well as allocate more appropriate hardware resources to the LXD backend. The configuration file can be used to initialise Bravetools as:

```bash
brave init --config config.yaml
```
```

# Remote backends

Bravetools can also use a remote LXD instance as a backend, allowing for seamless build and deployment of images
on that remote machine. If using a remote backend, users on Windows and Mac will not require Multipass to be installed locally
to use bravetools - instead they can contact an LXD instance running on a separate machine over TCP/IP. Alternatively, other Virtual Machine implementations such as VirtualBox could be set up manualy and used as a backend.

To do this, run `brave init --remote`. This will skip the setup of the local LXD server and multipass VM.
Then add a remote backend with `brave remote add local ...` providing the configuration options matching your
LXD instance as detailed [here](remotes.md).

For example:
```sh
# Initialize bravetools for first time
brave init --remote

# Add an existing remote LXD instance as a backend
brave remote add local https://10.0.0.10:8443 \
--profile bravetools-profile \
--storage bravetools-storage \
--network bravetoolsbr0 \
--password bravetools-password
```
6 changes: 5 additions & 1 deletion docs/installation/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,16 @@ nav_order: 2
## Supported platforms

Bravetools is available on a variety of Linux platforms, macOS, and Windows as a static binary.
The following table lists minimal requirements on each supported platform:
The following table lists minimal requirements on each supported platform to use bravetools with a backend
running on your local machine:

| Platform | Hardware | Software |
|:---------------------------|:------------------|:---------------|
| [Ubuntu 64-bit](ubuntu.md) | 1 GB Memory | [LXD >=3.0.3](https://documentation.ubuntu.com/lxd/en/latest/) |
| [macOS Mojave](macos.md) | 8 GB Memory | [Multipass](https://multipass.run/) |
| [Windows 10](windows.md) | 8 GB Memory | [Multipass](https://multipass.run/) |

If using a [remote backend](../docs/init.md#remote-backends) the above requirements do not apply - the bravetools binary
alone should be enough.

The easiest way to install Bravetools is to download the [latest stable release](https://github.com/bravetools/bravetools/releases) for your host platform and add it to your `$PATH`.
28 changes: 24 additions & 4 deletions platform/backend.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,16 +39,36 @@ type StorageUsage struct {
}

// NewHostBackend returns a new Backend from provided host Settings
func NewHostBackend(hostSetings HostSettings) (backend Backend, err error) {
backendType := hostSetings.BackendSettings.Type
func NewHostBackend(hostSettings HostSettings) (backend Backend, err error) {
backendType := hostSettings.BackendSettings.Type

switch backendType {
case "multipass":
backend = NewMultipass(hostSetings)
backend = NewMultipass(hostSettings)
case "lxd":
backend = NewLxd(hostSetings)
backend = NewLxd(hostSettings)
case "remote":
backend = &DummyBackend{}
default:
err = fmt.Errorf("backend type %q not supported", backendType)
}
return backend, err
}

// DummyBackend is a non-functional backend
type DummyBackend struct {
Settings HostSettings
}

func (d *DummyBackend) BraveBackendInit() error {
return nil
}
func (d *DummyBackend) Info() (Info, error) {
return Info{}, nil
}
func (d *DummyBackend) Running() (bool, error) {
return true, nil
}
func (d *DummyBackend) Start() error {
return nil
}
4 changes: 2 additions & 2 deletions platform/helpers.go
Original file line number Diff line number Diff line change
Expand Up @@ -234,7 +234,7 @@ func buildImage(bh *BraveHost, bravefile *shared.Bravefile) error {
return err
}

err = CheckStoragePoolSpace(lxdServer, bh.Settings.StoragePool.Name, img.Size)
err = CheckStoragePoolSpace(lxdServer, bh.Remote.Storage, img.Size)
if err := shared.CollectErrors(err, ctx.Err()); err != nil {
return err
}
Expand Down Expand Up @@ -289,7 +289,7 @@ func buildImage(bh *BraveHost, bravefile *shared.Bravefile) error {
if err := shared.CollectErrors(err, ctx.Err()); err != nil {
return err
}
err = CheckStoragePoolSpace(lxdServer, bh.Settings.StoragePool.Name, imgSize)
err = CheckStoragePoolSpace(lxdServer, bh.Remote.Storage, imgSize)
if err := shared.CollectErrors(err, ctx.Err()); err != nil {
return err
}
Expand Down
14 changes: 7 additions & 7 deletions platform/host.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@ type HostSettings struct {
Network Network `yaml:"network"`
BackendSettings BackendSettings `yaml:"backendsettings"`
Status string `yaml:"status"`
Remote string `yaml:"remote"`
}

// Storage ..
Expand Down Expand Up @@ -77,7 +76,7 @@ func NewBraveHost() (*BraveHost, error) {
}

// Load host remote if initialized
host.Remote, _ = LoadRemoteSettings(host.Settings.Remote)
host.Remote, _ = LoadRemoteSettings(host.Remote.Name)

host.Backend, err = NewHostBackend(host.Settings)
if err != nil {
Expand Down Expand Up @@ -153,7 +152,12 @@ func SetupHostConfiguration(params HostConfig, userHome string) (settings HostSe
settings.BackendSettings = backendSettings
}

settings.Remote = shared.BravetoolsRemote
if params.Backend == "remote" {
settings.BackendSettings = BackendSettings{
Type: "remote",
}
// settings.Remote = "remote"
}

doc, err := yaml.Marshal(settings)
if err != nil {
Expand Down Expand Up @@ -248,9 +252,5 @@ func loadHostSettings(userHome string) (HostSettings, error) {
return settings, errors.New("failed to parse configuration yaml: " + err.Error())
}

if settings.Remote == "" {
settings.Remote = shared.BravetoolsRemote
}

return settings, nil
}
4 changes: 4 additions & 0 deletions platform/host_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,8 @@ func (bh *BraveHost) UmountShare(unit string, target string) error {
if err != nil {
return errors.New("failed to umount " + target + ": " + err.Error())
}
default:
return fmt.Errorf("mounts are not supported for backend type %q", backend)
}

volume, _ := GetVolume(lxdServer, bh.Settings.StoragePool.Name)
Expand Down Expand Up @@ -531,6 +533,8 @@ func (bh *BraveHost) MountShare(source string, destUnit string, destPath string)
if err != nil {
return errors.New("failed to mount " + source + " to " + destUnit + ":" + destPath + " : " + err.Error())
}
default:
return fmt.Errorf("mounts are not supported for backend type %q", backend)
}

return nil
Expand Down