Skip to content

Commit

Permalink
Merge pull request #175 from Szubie/remote-resources
Browse files Browse the repository at this point in the history
Remote resources
  • Loading branch information
idroz committed Oct 6, 2022
2 parents 9dcc184 + ab8809a commit 70cd0a1
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 60 deletions.
23 changes: 18 additions & 5 deletions platform/host_api.go
Original file line number Diff line number Diff line change
Expand Up @@ -729,7 +729,7 @@ func (bh *BraveHost) BuildImage(bravefile shared.Bravefile) error {
if err != nil {
return err
}
err = CheckBackendDiskSpace(bh.Backend, img.Size)
err = CheckStoragePoolSpace(lxdServer, bh.Settings.StoragePool.Name, img.Size)
if err != nil {
return err
}
Expand Down Expand Up @@ -774,7 +774,7 @@ func (bh *BraveHost) BuildImage(bravefile shared.Bravefile) error {
if err != nil {
return err
}
err = CheckBackendDiskSpace(bh.Backend, imgSize)
err = CheckStoragePoolSpace(lxdServer, bh.Settings.StoragePool.Name, imgSize)
if err != nil {
return err
}
Expand Down Expand Up @@ -852,7 +852,7 @@ func (bh *BraveHost) BuildImage(bravefile shared.Bravefile) error {
}

// Create an image based on running container and export it. Image saved as tar.gz in project local directory.
unitFingerprint, err := Publish(lxdServer, bravefile.PlatformService.Name, imageStruct.String())
unitFingerprint, err := Publish(lxdServer, bravefile.PlatformService.Name, "")
defer DeleteImageByFingerprint(lxdServer, unitFingerprint)
if err := shared.CollectErrors(err, ctx.Err()); err != nil {
return errors.New("failed to publish image: " + err.Error())
Expand Down Expand Up @@ -1087,11 +1087,24 @@ func (bh *BraveHost) InitUnit(backend Backend, unitParams shared.Service) (err e
if err != nil {
return fmt.Errorf("failed to obtain image hash %q", unitParams.Image)
}
imgSize, err := localImageSize(imageStruct)
if err != nil {
return fmt.Errorf("failed to get image size for image %q", imageStruct.String())
}
defer DeleteImageByFingerprint(lxdServer, fingerprint)

// Resource checks
// TODO: this should use a profile
err = CheckResources(imageStruct, backend, &unitParams, bh)
if unitParams.Storage != "" {
err = CheckStoragePoolSpace(lxdServer, unitParams.Storage, imgSize)
if err != nil {
return err
}
}
err = CheckMemory(lxdServer, unitParams.Resources.RAM)
if err != nil {
return err
}
err = CheckHostPorts(deployRemote.URL, unitParams.Ports)
if err != nil {
return err
}
Expand Down
9 changes: 6 additions & 3 deletions platform/operations.go
Original file line number Diff line number Diff line change
Expand Up @@ -810,8 +810,8 @@ func Stop(lxdServer lxd.InstanceServer, name string) error {
}

// Publish unit
// lxc publish -f [remote]:[name] [remote]: --alias [name-version]
func Publish(lxdServer lxd.InstanceServer, name string, version string) (fingerprint string, err error) {
// lxc publish -f [remote]:[name] [remote]: --alias [name-suffix]
func Publish(lxdServer lxd.InstanceServer, name string, suffix string) (fingerprint string, err error) {
operation := shared.Info("Publishing " + name)
s := spinner.New(spinner.CharSets[14], 100*time.Millisecond, spinner.WithWriter(os.Stderr))
s.Suffix = " " + operation
Expand Down Expand Up @@ -864,7 +864,10 @@ func Publish(lxdServer lxd.InstanceServer, name string, version string) (fingerp
fingerprint = opAPI.Metadata["fingerprint"].(string)

aliasPost := api.ImageAliasesPost{}
aliasPost.Name = name + "-" + version
aliasPost.Name = name
if suffix != "" {
aliasPost.Name += "-" + suffix
}
aliasPost.Target = fingerprint
err = lxdServer.CreateImageAlias(aliasPost)
if err != nil {
Expand Down
85 changes: 37 additions & 48 deletions platform/resources.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,50 +2,52 @@ package platform

import (
"errors"
"fmt"
"math"
"net"
"net/url"
"strings"

"github.com/bravetools/bravetools/shared"
lxd "github.com/lxc/lxd/client"
)

// CheckResources ..
func CheckResources(image BravetoolsImage, backend Backend, unitParams *shared.Service, bh *BraveHost) error {
info, err := backend.Info()
// CheckMemory checks if the LXD server host has sufficient RAM to deploy requested unit
func CheckMemory(lxdServer lxd.InstanceServer, ramString string) error {
resources, err := lxdServer.GetServerResources()
if err != nil {
return errors.New("failed to connect to host: " + err.Error())
return errors.New("failed to retrieve LXD server resources: " + err.Error())
}

requestedImageSize, err := localImageSize(image)
if err != nil {
return err
}
freeDiskSpace, err := getFreeSpace(info.Disk)
requestedMemorySize, err := shared.SizeCountToInt(ramString)
if err != nil {
return err
}
freeMemorySize := resources.Memory.Total - resources.Memory.Used

if requestedImageSize*5 > freeDiskSpace {
return errors.New("requested unit size exceeds available disk space on bravetools host. To increase storage pool size modify $HOME/.bravetools/config.yml and run brave configure")
if uint64(requestedMemorySize) > freeMemorySize {
return errors.New("Requested unit memory (" + ramString + ") exceeds available memory on bravetools host")
}

requestedMemorySize, err := shared.SizeCountToInt(unitParams.Resources.RAM)
return nil
}

// CheckHostPorts ensures required forwarded ports are free by attempting to connect.
// If a connection is established the port is already taken
func CheckHostPorts(hostURL string, forwardedPorts []string) (err error) {
parsedURL, err := url.Parse(hostURL)
if err != nil {
return err
return fmt.Errorf("failed to parse host URL %q: %s", hostURL, err)
}
freeMemorySize, err := getFreeSpace(info.Memory)
host, _, err := net.SplitHostPort(parsedURL.Host)
if err != nil {
return err
}

if requestedMemorySize > freeMemorySize {
return errors.New("Requested unit memory (" + unitParams.Resources.RAM + ") exceeds available memory on bravetools host")
return fmt.Errorf("failed to parse host URL %q: %s", hostURL, err)
}

// Networking Checks
hostIP := info.IPv4
ports := unitParams.Ports
var hostPorts []string
if len(ports) > 0 {
for _, p := range ports {
if len(forwardedPorts) > 0 {
for _, p := range forwardedPorts {
ps := strings.Split(p, ":")
if len(ps) < 2 {
return errors.New("invalid port forwarding definition. Appropriate format is UNIT_PORT:HOST_PORT")
Expand All @@ -54,41 +56,28 @@ func CheckResources(image BravetoolsImage, backend Backend, unitParams *shared.S
}
}

err = shared.TCPPortStatus(hostIP, hostPorts)
err = shared.TCPPortStatus(host, hostPorts)
if err != nil {
return err
}

return nil
}

func getFreeSpace(storageUsage StorageUsage) (freeSpace int64, err error) {
usedStorageBytes, err := shared.SizeCountToInt(storageUsage.UsedStorage)
if err != nil {
return freeSpace, errors.New("failed to retrieve backend disk usage:" + err.Error())
}
totalStorageBytes, err := shared.SizeCountToInt(storageUsage.TotalStorage)
if err != nil {
return freeSpace, errors.New("failed to retrieve backend disk space:" + err.Error())
}

return totalStorageBytes - usedStorageBytes, nil
}

// CheckBackendDiskSpace checks whether backend has enough disk space for requested allocation
func CheckBackendDiskSpace(backend Backend, requestedSpace int64) (err error) {
info, err := backend.Info()
func CheckStoragePoolSpace(lxdServer lxd.InstanceServer, storagePool string, requestedSpace int64) (err error) {
res, err := lxdServer.GetStoragePoolResources(storagePool)
if err != nil {
return errors.New("Failed to connect to host: " + err.Error())
return fmt.Errorf("failed to retrieve storage information for storage pool %q from lxd server", storagePool)
}
freeSpace := res.Space.Total - res.Space.Used

freeSpace, err := getFreeSpace(info.Disk)
if err != nil {
return err
}

if requestedSpace >= freeSpace {
return errors.New("requested unit size exceeds available disk space on bravetools host. To increase storage pool size modify $HOME/.bravetools/config.yml and run brave configure")
if freeSpace <= uint64(requestedSpace) {
// Potential uint64 -> int64 int overflow - just setting to max for now
if freeSpace > math.MaxInt64 {
freeSpace = math.MaxInt64
}
return fmt.Errorf("requested size exceeds available space on storage pool - %q requested but %q available",
shared.FormatByteCountSI(requestedSpace), shared.FormatByteCountSI(int64(freeSpace)))
}

return nil
Expand Down
8 changes: 4 additions & 4 deletions shared/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ func Color(colorString string) func(...interface{}) string {
return sprint
}

func ping(ip string, port string) error {
address, err := net.ResolveTCPAddr("tcp", ip+":"+port)
func ping(host string, port string) error {
address, err := net.ResolveTCPAddr("tcp", host+":"+port)
if err != nil {
return err
}
Expand All @@ -71,9 +71,9 @@ func ping(ip string, port string) error {
}

// TCPPortStatus checks if multiple ports are available on the host
func TCPPortStatus(ip string, ports []string) error {
func TCPPortStatus(host string, ports []string) error {
for _, port := range ports {
err := ping(ip, port)
err := ping(host, port)
if err != nil {
return err
}
Expand Down

0 comments on commit 70cd0a1

Please sign in to comment.