github.com/juju/charm/v11@v11.2.0/lxdprofile.go (about)

     1  // Copyright 2018 Canonical Ltd.
     2  // Licensed under the LGPLv3, see LICENCE file for details.
     3  
     4  package charm
     5  
     6  import (
     7  	"fmt"
     8  	"io"
     9  	"io/ioutil"
    10  	"strings"
    11  
    12  	"github.com/juju/collections/set"
    13  	"github.com/juju/errors"
    14  	"gopkg.in/yaml.v2"
    15  )
    16  
    17  // LXDProfiler defines a way to access a LXDProfile from a charm.
    18  type LXDProfiler interface {
    19  	// LXDProfile returns the LXDProfile found in lxd-profile.yaml of the charm
    20  	LXDProfile() *LXDProfile
    21  }
    22  
    23  // LXDProfile is the same as ProfilePut defined in github.com/lxc/lxd/shared/api/profile.go
    24  type LXDProfile struct {
    25  	Config      map[string]string            `json:"config" yaml:"config"`
    26  	Description string                       `json:"description" yaml:"description"`
    27  	Devices     map[string]map[string]string `json:"devices" yaml:"devices"`
    28  }
    29  
    30  // NewLXDProfile creates a LXDProfile with the internal data structures
    31  // initialised  to non nil values.
    32  func NewLXDProfile() *LXDProfile {
    33  	return &LXDProfile{
    34  		Config:  map[string]string{},
    35  		Devices: map[string]map[string]string{},
    36  	}
    37  }
    38  
    39  // ReadLXDProfile reads in a LXDProfile from a charm's lxd-profile.yaml.
    40  // It is not validated at this point so that the caller can choose to override
    41  // any validation.
    42  func ReadLXDProfile(r io.Reader) (*LXDProfile, error) {
    43  	data, err := ioutil.ReadAll(r)
    44  	if err != nil {
    45  		return nil, err
    46  	}
    47  	profile := NewLXDProfile()
    48  	if err := yaml.Unmarshal(data, profile); err != nil {
    49  		return nil, errors.Annotate(err, "failed to unmarshall lxd-profile.yaml")
    50  	}
    51  	return profile, nil
    52  }
    53  
    54  // ValidateConfigDevices validates the Config and Devices properties of the LXDProfile.
    55  // WhiteList devices: unix-char, unix-block, gpu, usb.
    56  // BlackList config: boot*, limits* and migration*.
    57  // An empty profile will not return an error.
    58  func (profile *LXDProfile) ValidateConfigDevices() error {
    59  	for _, val := range profile.Devices {
    60  		goodDevs := set.NewStrings("unix-char", "unix-block", "gpu", "usb")
    61  		if devType, ok := val["type"]; ok {
    62  			if !goodDevs.Contains(devType) {
    63  				return fmt.Errorf("invalid lxd-profile.yaml: contains device type %q", devType)
    64  			}
    65  		}
    66  	}
    67  	for key := range profile.Config {
    68  		if strings.HasPrefix(key, "boot") ||
    69  			strings.HasPrefix(key, "limits") ||
    70  			strings.HasPrefix(key, "migration") {
    71  			return fmt.Errorf("invalid lxd-profile.yaml: contains config value %q", key)
    72  		}
    73  	}
    74  	return nil
    75  }
    76  
    77  // Empty returns true if neither devices nor config have been defined in the profile.
    78  func (profile *LXDProfile) Empty() bool {
    79  	return len(profile.Devices) < 1 && len(profile.Config) < 1
    80  }