github.com/mhilton/juju-juju@v0.0.0-20150901100907-a94dd2c73455/instance/placement.go (about) 1 // Copyright 2014 Canonical Ltd. 2 // Licensed under the AGPLv3, see LICENCE file for details. 3 4 package instance 5 6 import ( 7 "fmt" 8 "strings" 9 10 "github.com/juju/names" 11 ) 12 13 const ( 14 // MachineScope is a special scope name that is used 15 // for machine placement directives (e.g. --to 0). 16 MachineScope = "#" 17 ) 18 19 var ErrPlacementScopeMissing = fmt.Errorf("placement scope missing") 20 21 // Placement defines a placement directive, which has a scope 22 // and a value that is scope-specific. 23 type Placement struct { 24 // Scope is the scope of the placement directive. Scope may 25 // be a container type (lxc, kvm), instance.MachineScope, or 26 // an environment name. 27 // 28 // If Scope is empty, then it must be inferred from the context. 29 Scope string 30 31 // Directive is a scope-specific placement directive. 32 // 33 // For MachineScope or a container scope, this may be empty or 34 // the ID of an existing machine. 35 Directive string 36 } 37 38 func (p *Placement) String() string { 39 return fmt.Sprintf("%s:%s", p.Scope, p.Directive) 40 } 41 42 func isContainerType(s string) bool { 43 _, err := ParseContainerType(s) 44 return err == nil 45 } 46 47 // ParsePlacement attempts to parse the specified string and create a 48 // corresponding Placement structure. 49 // 50 // If the placement directive is non-empty and missing a scope, 51 // ErrPlacementScopeMissing will be returned as well as a Placement 52 // with an empty Scope field. 53 func ParsePlacement(directive string) (*Placement, error) { 54 if directive == "" { 55 return nil, nil 56 } 57 if colon := strings.IndexRune(directive, ':'); colon != -1 { 58 scope, directive := directive[:colon], directive[colon+1:] 59 if scope == "" { 60 return nil, ErrPlacementScopeMissing 61 } 62 // Sanity check: machine/container scopes require a machine ID as the value. 63 if (scope == MachineScope || isContainerType(scope)) && !names.IsValidMachine(directive) { 64 return nil, fmt.Errorf("invalid value %q for %q scope: expected machine-id", directive, scope) 65 } 66 return &Placement{Scope: scope, Directive: directive}, nil 67 } 68 if names.IsValidMachine(directive) { 69 return &Placement{Scope: MachineScope, Directive: directive}, nil 70 } 71 if isContainerType(directive) { 72 return &Placement{Scope: directive}, nil 73 } 74 return nil, ErrPlacementScopeMissing 75 } 76 77 // MustParsePlacement attempts to parse the specified string and create 78 // a corresponding Placement structure, panicking if an error occurs. 79 func MustParsePlacement(directive string) *Placement { 80 placement, err := ParsePlacement(directive) 81 if err != nil { 82 panic(err) 83 } 84 return placement 85 }