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 }