~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/github.com/juju/juju/instance/placement.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
        "gopkg.in/juju/names.v2"
 
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 (lxd, 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 `json:"scope"`
 
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 `json:"directive"`
 
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
}