github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/instance/namespace.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package instance
     5  
     6  import (
     7  	"strings"
     8  
     9  	"github.com/juju/errors"
    10  	"gopkg.in/juju/names.v2"
    11  )
    12  
    13  // uuidSuffixDigits defines how many of the uuid digits to use.
    14  // Since the NewNamespace function asserts that the modelUUID is valid, we know
    15  // it follows the UUID string format that ends with eight hex digits.
    16  const uuidSuffixDigits = 6
    17  
    18  // Namespace provides a way to generate machine hostanmes with a given prefix.
    19  type Namespace interface {
    20  	// Prefix returns the common part of the hostnames. i.e. 'juju-xxxxxx-'
    21  	Prefix() string
    22  
    23  	// Hostname returns a name suitable to be used for a machine hostname.
    24  	// This function returns an error if the machine tags is invalid.
    25  	Hostname(machineID string) (string, error)
    26  
    27  	// MachineTag does the reverse of the Hostname method, and extracts the
    28  	// Tag from the hostname.
    29  	MachineTag(hostname string) (names.MachineTag, error)
    30  
    31  	// Value returns the input prefixed with the namespace prefix.
    32  	Value(string) string
    33  }
    34  
    35  type namespace struct {
    36  	name string
    37  }
    38  
    39  // NewNamespace returns a Namespace identified by the last six hex digits of the
    40  // model UUID. NewNamespace returns an error if the model tag is invalid.
    41  func NewNamespace(modelUUID string) (Namespace, error) {
    42  	if !names.IsValidModel(modelUUID) {
    43  		return nil, errors.Errorf("model ID %q is not a valid model", modelUUID)
    44  	}
    45  	// The suffix is the last six hex digits of the model uuid.
    46  	suffix := modelUUID[len(modelUUID)-uuidSuffixDigits:]
    47  
    48  	return &namespace{name: suffix}, nil
    49  }
    50  
    51  // Hostname implements Namespace.
    52  func (n *namespace) Hostname(machineID string) (string, error) {
    53  	if !names.IsValidMachine(machineID) {
    54  		return "", errors.Errorf("machine ID %q is not a valid machine", machineID)
    55  	}
    56  	machineID = strings.Replace(machineID, "/", "-", -1)
    57  	return n.Value(machineID), nil
    58  }
    59  
    60  // Value returns the input prefixed with the namespace prefix.
    61  func (n *namespace) Value(s string) string {
    62  	return n.Prefix() + s
    63  }
    64  
    65  // Hostname implements Namespace.
    66  func (n *namespace) MachineTag(hostname string) (names.MachineTag, error) {
    67  	prefix := n.Prefix()
    68  	if !strings.HasPrefix(hostname, prefix) {
    69  		return names.MachineTag{}, errors.Errorf("hostname %q not from namespace %q", hostname, prefix)
    70  	}
    71  	id := hostname[len(prefix):]
    72  	id = strings.Replace(id, "-", "/", -1)
    73  	if !names.IsValidMachine(id) {
    74  		return names.MachineTag{}, errors.Errorf("unexpected machine id %q", id)
    75  	}
    76  	return names.NewMachineTag(id), nil
    77  }
    78  
    79  // Prefix implements Namespace.
    80  func (n *namespace) Prefix() string {
    81  	return "juju-" + n.name + "-"
    82  }