github.com/wallyworld/juju@v0.0.0-20161013125918-6cf1bc9d917a/core/description/model.go (about)

     1  // Copyright 2016 Canonical Ltd.
     2  // Licensed under the AGPLv3, see LICENCE file for details.
     3  
     4  package description
     5  
     6  import (
     7  	"net"
     8  	"sort"
     9  	"strings"
    10  
    11  	"github.com/juju/errors"
    12  	"github.com/juju/schema"
    13  	"github.com/juju/utils/set"
    14  	"github.com/juju/version"
    15  	"gopkg.in/juju/names.v2"
    16  	"gopkg.in/yaml.v2"
    17  )
    18  
    19  // ModelArgs represent the bare minimum information that is needed
    20  // to represent a model.
    21  type ModelArgs struct {
    22  	Owner              names.UserTag
    23  	Config             map[string]interface{}
    24  	LatestToolsVersion version.Number
    25  	Blocks             map[string]string
    26  	Cloud              string
    27  	CloudRegion        string
    28  	CloudCredential    string
    29  }
    30  
    31  // NewModel returns a Model based on the args specified.
    32  func NewModel(args ModelArgs) Model {
    33  	m := &model{
    34  		Version:             1,
    35  		Owner_:              args.Owner.Id(),
    36  		Config_:             args.Config,
    37  		LatestToolsVersion_: args.LatestToolsVersion,
    38  		Sequences_:          make(map[string]int),
    39  		Blocks_:             args.Blocks,
    40  		Cloud_:              args.Cloud,
    41  		CloudRegion_:        args.CloudRegion,
    42  		CloudCredential_:    args.CloudCredential,
    43  	}
    44  	m.setUsers(nil)
    45  	m.setMachines(nil)
    46  	m.setApplications(nil)
    47  	m.setRelations(nil)
    48  	m.setSpaces(nil)
    49  	m.setLinkLayerDevices(nil)
    50  	m.setSubnets(nil)
    51  	m.setIPAddresses(nil)
    52  	m.setSSHHostKeys(nil)
    53  	m.setCloudImageMetadatas(nil)
    54  	m.setActions(nil)
    55  	m.setVolumes(nil)
    56  	m.setFilesystems(nil)
    57  	m.setStorages(nil)
    58  	m.setStoragePools(nil)
    59  	return m
    60  }
    61  
    62  // Serialize mirrors the Deserialize method, and makes sure that
    63  // the same serialization method is used.
    64  func Serialize(model Model) ([]byte, error) {
    65  	return yaml.Marshal(model)
    66  }
    67  
    68  // Deserialize constructs a Model from a serialized YAML byte stream. The
    69  // normal use for this is to construct the Model representation after getting
    70  // the byte stream from an API connection or read from a file.
    71  func Deserialize(bytes []byte) (Model, error) {
    72  	var source map[string]interface{}
    73  	err := yaml.Unmarshal(bytes, &source)
    74  	if err != nil {
    75  		return nil, errors.Trace(err)
    76  	}
    77  
    78  	model, err := importModel(source)
    79  	if err != nil {
    80  		return nil, errors.Trace(err)
    81  	}
    82  	return model, nil
    83  }
    84  
    85  // parseLinkLayerDeviceGlobalKey is used to validate that the parent device
    86  // referenced by a LinkLayerDevice exists. Copied from state to avoid exporting
    87  // and will be replaced by device.ParentMachineID() at some point.
    88  func parseLinkLayerDeviceGlobalKey(globalKey string) (machineID, deviceName string, canBeGlobalKey bool) {
    89  	if !strings.Contains(globalKey, "#") {
    90  		// Can't be a global key.
    91  		return "", "", false
    92  	}
    93  	keyParts := strings.Split(globalKey, "#")
    94  	if len(keyParts) != 4 || (keyParts[0] != "m" && keyParts[2] != "d") {
    95  		// Invalid global key format.
    96  		return "", "", true
    97  	}
    98  	machineID, deviceName = keyParts[1], keyParts[3]
    99  	return machineID, deviceName, true
   100  }
   101  
   102  // parentId returns the id of the host machine if machineId a container id, or ""
   103  // if machineId is not for a container.
   104  func parentId(machineId string) string {
   105  	idParts := strings.Split(machineId, "/")
   106  	if len(idParts) < 3 {
   107  		return ""
   108  	}
   109  	return strings.Join(idParts[:len(idParts)-2], "/")
   110  }
   111  
   112  type model struct {
   113  	Version int `yaml:"version"`
   114  
   115  	Owner_  string                 `yaml:"owner"`
   116  	Config_ map[string]interface{} `yaml:"config"`
   117  	Blocks_ map[string]string      `yaml:"blocks,omitempty"`
   118  
   119  	LatestToolsVersion_ version.Number `yaml:"latest-tools,omitempty"`
   120  
   121  	Users_            users            `yaml:"users"`
   122  	Machines_         machines         `yaml:"machines"`
   123  	Applications_     applications     `yaml:"applications"`
   124  	Relations_        relations        `yaml:"relations"`
   125  	Spaces_           spaces           `yaml:"spaces"`
   126  	LinkLayerDevices_ linklayerdevices `yaml:"link-layer-devices"`
   127  	IPAddresses_      ipaddresses      `yaml:"ip-addresses"`
   128  	Subnets_          subnets          `yaml:"subnets"`
   129  
   130  	CloudImageMetadata_ cloudimagemetadataset `yaml:"cloud-image-metadata"`
   131  
   132  	Actions_ actions `yaml:"actions"`
   133  
   134  	SSHHostKeys_ sshHostKeys `yaml:"ssh-host-keys"`
   135  
   136  	Sequences_ map[string]int `yaml:"sequences"`
   137  
   138  	Annotations_ `yaml:"annotations,omitempty"`
   139  
   140  	Constraints_ *constraints `yaml:"constraints,omitempty"`
   141  
   142  	Cloud_           string `yaml:"cloud"`
   143  	CloudRegion_     string `yaml:"cloud-region,omitempty"`
   144  	CloudCredential_ string `yaml:"cloud-credential,omitempty"`
   145  
   146  	Volumes_      volumes      `yaml:"volumes"`
   147  	Filesystems_  filesystems  `yaml:"filesystems"`
   148  	Storages_     storages     `yaml:"storages"`
   149  	StoragePools_ storagepools `yaml:"storage-pools"`
   150  }
   151  
   152  func (m *model) Tag() names.ModelTag {
   153  	// Here we make the assumption that the environment UUID is set
   154  	// correctly in the Config.
   155  	value := m.Config_["uuid"]
   156  	// Explicitly ignore the 'ok' aspect of the cast. If we don't have it
   157  	// and it is wrong, we panic. Here we fully expect it to exist, but
   158  	// paranoia says 'never panic', so worst case is we have an empty string.
   159  	uuid, _ := value.(string)
   160  	return names.NewModelTag(uuid)
   161  }
   162  
   163  // Owner implements Model.
   164  func (m *model) Owner() names.UserTag {
   165  	return names.NewUserTag(m.Owner_)
   166  }
   167  
   168  // Config implements Model.
   169  func (m *model) Config() map[string]interface{} {
   170  	// TODO: consider returning a deep copy.
   171  	return m.Config_
   172  }
   173  
   174  // UpdateConfig implements Model.
   175  func (m *model) UpdateConfig(config map[string]interface{}) {
   176  	for key, value := range config {
   177  		m.Config_[key] = value
   178  	}
   179  }
   180  
   181  // LatestToolsVersion implements Model.
   182  func (m *model) LatestToolsVersion() version.Number {
   183  	return m.LatestToolsVersion_
   184  }
   185  
   186  // Blocks implements Model.
   187  func (m *model) Blocks() map[string]string {
   188  	return m.Blocks_
   189  }
   190  
   191  // Implement length-based sort with ByLen type.
   192  type ByName []User
   193  
   194  func (a ByName) Len() int           { return len(a) }
   195  func (a ByName) Less(i, j int) bool { return a[i].Name().Id() < a[j].Name().Id() }
   196  func (a ByName) Swap(i, j int)      { a[i], a[j] = a[j], a[i] }
   197  
   198  // Users implements Model.
   199  func (m *model) Users() []User {
   200  	var result []User
   201  	for _, user := range m.Users_.Users_ {
   202  		result = append(result, user)
   203  	}
   204  	sort.Sort(ByName(result))
   205  	return result
   206  }
   207  
   208  // AddUser implements Model.
   209  func (m *model) AddUser(args UserArgs) {
   210  	m.Users_.Users_ = append(m.Users_.Users_, newUser(args))
   211  }
   212  
   213  func (m *model) setUsers(userList []*user) {
   214  	m.Users_ = users{
   215  		Version: 1,
   216  		Users_:  userList,
   217  	}
   218  }
   219  
   220  // Machines implements Model.
   221  func (m *model) Machines() []Machine {
   222  	var result []Machine
   223  	for _, machine := range m.Machines_.Machines_ {
   224  		result = append(result, machine)
   225  	}
   226  	return result
   227  }
   228  
   229  // AddMachine implements Model.
   230  func (m *model) AddMachine(args MachineArgs) Machine {
   231  	machine := newMachine(args)
   232  	m.Machines_.Machines_ = append(m.Machines_.Machines_, machine)
   233  	return machine
   234  }
   235  
   236  func (m *model) setMachines(machineList []*machine) {
   237  	m.Machines_ = machines{
   238  		Version:   1,
   239  		Machines_: machineList,
   240  	}
   241  }
   242  
   243  // Applications implements Model.
   244  func (m *model) Applications() []Application {
   245  	var result []Application
   246  	for _, application := range m.Applications_.Applications_ {
   247  		result = append(result, application)
   248  	}
   249  	return result
   250  }
   251  
   252  func (m *model) application(name string) *application {
   253  	for _, application := range m.Applications_.Applications_ {
   254  		if application.Name() == name {
   255  			return application
   256  		}
   257  	}
   258  	return nil
   259  }
   260  
   261  // AddApplication implements Model.
   262  func (m *model) AddApplication(args ApplicationArgs) Application {
   263  	application := newApplication(args)
   264  	m.Applications_.Applications_ = append(m.Applications_.Applications_, application)
   265  	return application
   266  }
   267  
   268  func (m *model) setApplications(applicationList []*application) {
   269  	m.Applications_ = applications{
   270  		Version:       1,
   271  		Applications_: applicationList,
   272  	}
   273  }
   274  
   275  // Relations implements Model.
   276  func (m *model) Relations() []Relation {
   277  	var result []Relation
   278  	for _, relation := range m.Relations_.Relations_ {
   279  		result = append(result, relation)
   280  	}
   281  	return result
   282  }
   283  
   284  // AddRelation implements Model.
   285  func (m *model) AddRelation(args RelationArgs) Relation {
   286  	relation := newRelation(args)
   287  	m.Relations_.Relations_ = append(m.Relations_.Relations_, relation)
   288  	return relation
   289  }
   290  
   291  func (m *model) setRelations(relationList []*relation) {
   292  	m.Relations_ = relations{
   293  		Version:    1,
   294  		Relations_: relationList,
   295  	}
   296  }
   297  
   298  // Spaces implements Model.
   299  func (m *model) Spaces() []Space {
   300  	var result []Space
   301  	for _, space := range m.Spaces_.Spaces_ {
   302  		result = append(result, space)
   303  	}
   304  	return result
   305  }
   306  
   307  // AddSpace implements Model.
   308  func (m *model) AddSpace(args SpaceArgs) Space {
   309  	space := newSpace(args)
   310  	m.Spaces_.Spaces_ = append(m.Spaces_.Spaces_, space)
   311  	return space
   312  }
   313  
   314  func (m *model) setSpaces(spaceList []*space) {
   315  	m.Spaces_ = spaces{
   316  		Version: 1,
   317  		Spaces_: spaceList,
   318  	}
   319  }
   320  
   321  // LinkLayerDevices implements Model.
   322  func (m *model) LinkLayerDevices() []LinkLayerDevice {
   323  	var result []LinkLayerDevice
   324  	for _, device := range m.LinkLayerDevices_.LinkLayerDevices_ {
   325  		result = append(result, device)
   326  	}
   327  	return result
   328  }
   329  
   330  // AddLinkLayerDevice implements Model.
   331  func (m *model) AddLinkLayerDevice(args LinkLayerDeviceArgs) LinkLayerDevice {
   332  	device := newLinkLayerDevice(args)
   333  	m.LinkLayerDevices_.LinkLayerDevices_ = append(m.LinkLayerDevices_.LinkLayerDevices_, device)
   334  	return device
   335  }
   336  
   337  func (m *model) setLinkLayerDevices(devicesList []*linklayerdevice) {
   338  	m.LinkLayerDevices_ = linklayerdevices{
   339  		Version:           1,
   340  		LinkLayerDevices_: devicesList,
   341  	}
   342  }
   343  
   344  // Subnets implements Model.
   345  func (m *model) Subnets() []Subnet {
   346  	var result []Subnet
   347  	for _, subnet := range m.Subnets_.Subnets_ {
   348  		result = append(result, subnet)
   349  	}
   350  	return result
   351  }
   352  
   353  // AddSubnet implemets Model.
   354  func (m *model) AddSubnet(args SubnetArgs) Subnet {
   355  	subnet := newSubnet(args)
   356  	m.Subnets_.Subnets_ = append(m.Subnets_.Subnets_, subnet)
   357  	return subnet
   358  }
   359  
   360  func (m *model) setSubnets(subnetList []*subnet) {
   361  	m.Subnets_ = subnets{
   362  		Version:  1,
   363  		Subnets_: subnetList,
   364  	}
   365  }
   366  
   367  // IPAddresses implements Model.
   368  func (m *model) IPAddresses() []IPAddress {
   369  	var result []IPAddress
   370  	for _, addr := range m.IPAddresses_.IPAddresses_ {
   371  		result = append(result, addr)
   372  	}
   373  	return result
   374  }
   375  
   376  // AddIPAddress implements Model.
   377  func (m *model) AddIPAddress(args IPAddressArgs) IPAddress {
   378  	addr := newIPAddress(args)
   379  	m.IPAddresses_.IPAddresses_ = append(m.IPAddresses_.IPAddresses_, addr)
   380  	return addr
   381  }
   382  
   383  func (m *model) setIPAddresses(addressesList []*ipaddress) {
   384  	m.IPAddresses_ = ipaddresses{
   385  		Version:      1,
   386  		IPAddresses_: addressesList,
   387  	}
   388  }
   389  
   390  // SSHHostKeys implements Model.
   391  func (m *model) SSHHostKeys() []SSHHostKey {
   392  	var result []SSHHostKey
   393  	for _, addr := range m.SSHHostKeys_.SSHHostKeys_ {
   394  		result = append(result, addr)
   395  	}
   396  	return result
   397  }
   398  
   399  // AddSSHHostKey implements Model.
   400  func (m *model) AddSSHHostKey(args SSHHostKeyArgs) SSHHostKey {
   401  	addr := newSSHHostKey(args)
   402  	m.SSHHostKeys_.SSHHostKeys_ = append(m.SSHHostKeys_.SSHHostKeys_, addr)
   403  	return addr
   404  }
   405  
   406  func (m *model) setSSHHostKeys(addressesList []*sshHostKey) {
   407  	m.SSHHostKeys_ = sshHostKeys{
   408  		Version:      1,
   409  		SSHHostKeys_: addressesList,
   410  	}
   411  }
   412  
   413  // CloudImageMetadatas implements Model.
   414  func (m *model) CloudImageMetadata() []CloudImageMetadata {
   415  	var result []CloudImageMetadata
   416  	for _, addr := range m.CloudImageMetadata_.CloudImageMetadata_ {
   417  		result = append(result, addr)
   418  	}
   419  	return result
   420  }
   421  
   422  // Actions implements Model.
   423  func (m *model) Actions() []Action {
   424  	var result []Action
   425  	for _, addr := range m.Actions_.Actions_ {
   426  		result = append(result, addr)
   427  	}
   428  	return result
   429  }
   430  
   431  // AddCloudImageMetadata implements Model.
   432  func (m *model) AddCloudImageMetadata(args CloudImageMetadataArgs) CloudImageMetadata {
   433  	addr := newCloudImageMetadata(args)
   434  	m.CloudImageMetadata_.CloudImageMetadata_ = append(m.CloudImageMetadata_.CloudImageMetadata_, addr)
   435  	return addr
   436  }
   437  
   438  func (m *model) setCloudImageMetadatas(cloudimagemetadataList []*cloudimagemetadata) {
   439  	m.CloudImageMetadata_ = cloudimagemetadataset{
   440  		Version:             1,
   441  		CloudImageMetadata_: cloudimagemetadataList,
   442  	}
   443  }
   444  
   445  // AddAction implements Model.
   446  func (m *model) AddAction(args ActionArgs) Action {
   447  	addr := newAction(args)
   448  	m.Actions_.Actions_ = append(m.Actions_.Actions_, addr)
   449  	return addr
   450  }
   451  
   452  func (m *model) setActions(actionsList []*action) {
   453  	m.Actions_ = actions{
   454  		Version:  1,
   455  		Actions_: actionsList,
   456  	}
   457  }
   458  
   459  // Sequences implements Model.
   460  func (m *model) Sequences() map[string]int {
   461  	return m.Sequences_
   462  }
   463  
   464  // SetSequence implements Model.
   465  func (m *model) SetSequence(name string, value int) {
   466  	m.Sequences_[name] = value
   467  }
   468  
   469  // Constraints implements HasConstraints.
   470  func (m *model) Constraints() Constraints {
   471  	if m.Constraints_ == nil {
   472  		return nil
   473  	}
   474  	return m.Constraints_
   475  }
   476  
   477  // SetConstraints implements HasConstraints.
   478  func (m *model) SetConstraints(args ConstraintsArgs) {
   479  	m.Constraints_ = newConstraints(args)
   480  }
   481  
   482  // Cloud implements Model.
   483  func (m *model) Cloud() string {
   484  	return m.Cloud_
   485  }
   486  
   487  // CloudRegion implements Model.
   488  func (m *model) CloudRegion() string {
   489  	return m.CloudRegion_
   490  }
   491  
   492  // CloudCredential implements Model.
   493  func (m *model) CloudCredential() string {
   494  	return m.CloudCredential_
   495  }
   496  
   497  // Volumes implements Model.
   498  func (m *model) Volumes() []Volume {
   499  	var result []Volume
   500  	for _, volume := range m.Volumes_.Volumes_ {
   501  		result = append(result, volume)
   502  	}
   503  	return result
   504  }
   505  
   506  // AddVolume implemets Model.
   507  func (m *model) AddVolume(args VolumeArgs) Volume {
   508  	volume := newVolume(args)
   509  	m.Volumes_.Volumes_ = append(m.Volumes_.Volumes_, volume)
   510  	return volume
   511  }
   512  
   513  func (m *model) setVolumes(volumeList []*volume) {
   514  	m.Volumes_ = volumes{
   515  		Version:  1,
   516  		Volumes_: volumeList,
   517  	}
   518  }
   519  
   520  // Filesystems implements Model.
   521  func (m *model) Filesystems() []Filesystem {
   522  	var result []Filesystem
   523  	for _, filesystem := range m.Filesystems_.Filesystems_ {
   524  		result = append(result, filesystem)
   525  	}
   526  	return result
   527  }
   528  
   529  // AddFilesystem implemets Model.
   530  func (m *model) AddFilesystem(args FilesystemArgs) Filesystem {
   531  	filesystem := newFilesystem(args)
   532  	m.Filesystems_.Filesystems_ = append(m.Filesystems_.Filesystems_, filesystem)
   533  	return filesystem
   534  }
   535  
   536  func (m *model) setFilesystems(filesystemList []*filesystem) {
   537  	m.Filesystems_ = filesystems{
   538  		Version:      1,
   539  		Filesystems_: filesystemList,
   540  	}
   541  }
   542  
   543  // Storages implements Model.
   544  func (m *model) Storages() []Storage {
   545  	var result []Storage
   546  	for _, storage := range m.Storages_.Storages_ {
   547  		result = append(result, storage)
   548  	}
   549  	return result
   550  }
   551  
   552  // AddStorage implemets Model.
   553  func (m *model) AddStorage(args StorageArgs) Storage {
   554  	storage := newStorage(args)
   555  	m.Storages_.Storages_ = append(m.Storages_.Storages_, storage)
   556  	return storage
   557  }
   558  
   559  func (m *model) setStorages(storageList []*storage) {
   560  	m.Storages_ = storages{
   561  		Version:   1,
   562  		Storages_: storageList,
   563  	}
   564  }
   565  
   566  // StoragePools implements Model.
   567  func (m *model) StoragePools() []StoragePool {
   568  	var result []StoragePool
   569  	for _, pool := range m.StoragePools_.Pools_ {
   570  		result = append(result, pool)
   571  	}
   572  	return result
   573  }
   574  
   575  // AddStoragePool implemets Model.
   576  func (m *model) AddStoragePool(args StoragePoolArgs) StoragePool {
   577  	pool := newStoragePool(args)
   578  	m.StoragePools_.Pools_ = append(m.StoragePools_.Pools_, pool)
   579  	return pool
   580  }
   581  
   582  func (m *model) setStoragePools(poolList []*storagepool) {
   583  	m.StoragePools_ = storagepools{
   584  		Version: 1,
   585  		Pools_:  poolList,
   586  	}
   587  }
   588  
   589  // Validate implements Model.
   590  func (m *model) Validate() error {
   591  	// A model needs an owner.
   592  	if m.Owner_ == "" {
   593  		return errors.NotValidf("missing model owner")
   594  	}
   595  	allMachines := set.NewStrings()
   596  	unitsWithOpenPorts := set.NewStrings()
   597  	for _, machine := range m.Machines_.Machines_ {
   598  		if err := m.validateMachine(machine, allMachines, unitsWithOpenPorts); err != nil {
   599  			return errors.Trace(err)
   600  		}
   601  	}
   602  	allApplications := set.NewStrings()
   603  	allUnits := set.NewStrings()
   604  	for _, application := range m.Applications_.Applications_ {
   605  		if err := application.Validate(); err != nil {
   606  			return errors.Trace(err)
   607  		}
   608  		allApplications.Add(application.Name())
   609  		allUnits = allUnits.Union(application.unitNames())
   610  	}
   611  	// Make sure that all the unit names specified in machine opened ports
   612  	// exist as units of applications.
   613  	unknownUnitsWithPorts := unitsWithOpenPorts.Difference(allUnits)
   614  	if len(unknownUnitsWithPorts) > 0 {
   615  		return errors.Errorf("unknown unit names in open ports: %s", unknownUnitsWithPorts.SortedValues())
   616  	}
   617  
   618  	err := m.validateRelations()
   619  	if err != nil {
   620  		return errors.Trace(err)
   621  	}
   622  
   623  	err = m.validateSubnets()
   624  	if err != nil {
   625  		return errors.Trace(err)
   626  	}
   627  
   628  	err = m.validateLinkLayerDevices()
   629  	if err != nil {
   630  		return errors.Trace(err)
   631  	}
   632  	err = m.validateAddresses()
   633  	if err != nil {
   634  		return errors.Trace(err)
   635  	}
   636  
   637  	err = m.validateStorage(allMachines, allApplications, allUnits)
   638  	if err != nil {
   639  		return errors.Trace(err)
   640  	}
   641  
   642  	return nil
   643  }
   644  
   645  func (m *model) validateMachine(machine Machine, allMachineIDs, unitsWithOpenPorts set.Strings) error {
   646  	if err := machine.Validate(); err != nil {
   647  		return errors.Trace(err)
   648  	}
   649  	allMachineIDs.Add(machine.Id())
   650  	for _, op := range machine.OpenedPorts() {
   651  		for _, pr := range op.OpenPorts() {
   652  			unitsWithOpenPorts.Add(pr.UnitName())
   653  		}
   654  	}
   655  	for _, container := range machine.Containers() {
   656  		err := m.validateMachine(container, allMachineIDs, unitsWithOpenPorts)
   657  		if err != nil {
   658  			return errors.Trace(err)
   659  		}
   660  	}
   661  	return nil
   662  }
   663  
   664  func (m *model) validateStorage(allMachineIDs, allApplications, allUnits set.Strings) error {
   665  	appsAndUnits := allApplications.Union(allUnits)
   666  	allStorage := set.NewStrings()
   667  	for i, storage := range m.Storages_.Storages_ {
   668  		if err := storage.Validate(); err != nil {
   669  			return errors.Annotatef(err, "storage[%d]", i)
   670  		}
   671  		allStorage.Add(storage.Tag().Id())
   672  		owner, err := storage.Owner()
   673  		if err != nil {
   674  			return errors.Wrap(err, errors.NotValidf("storage[%d] owner (%s)", i, owner))
   675  		}
   676  		ownerID := owner.Id()
   677  		if !appsAndUnits.Contains(ownerID) {
   678  			return errors.NotValidf("storage[%d] owner (%s)", i, ownerID)
   679  		}
   680  		for _, unit := range storage.Attachments() {
   681  			if !allUnits.Contains(unit.Id()) {
   682  				return errors.NotValidf("storage[%d] attachment referencing unknown unit %q", i, unit)
   683  			}
   684  		}
   685  	}
   686  	allVolumes := set.NewStrings()
   687  	for i, volume := range m.Volumes_.Volumes_ {
   688  		if err := volume.Validate(); err != nil {
   689  			return errors.Annotatef(err, "volume[%d]", i)
   690  		}
   691  		allVolumes.Add(volume.Tag().Id())
   692  		if storeID := volume.Storage().Id(); storeID != "" && !allStorage.Contains(storeID) {
   693  			return errors.NotValidf("volume[%d] referencing unknown storage %q", i, storeID)
   694  		}
   695  		for j, attachment := range volume.Attachments() {
   696  			if machineID := attachment.Machine().Id(); !allMachineIDs.Contains(machineID) {
   697  				return errors.NotValidf("volume[%d].attachment[%d] referencing unknown machine %q", i, j, machineID)
   698  			}
   699  		}
   700  	}
   701  	for i, filesystem := range m.Filesystems_.Filesystems_ {
   702  		if err := filesystem.Validate(); err != nil {
   703  			return errors.Annotatef(err, "filesystem[%d]", i)
   704  		}
   705  		if storeID := filesystem.Storage().Id(); storeID != "" && !allStorage.Contains(storeID) {
   706  			return errors.NotValidf("filesystem[%d] referencing unknown storage %q", i, storeID)
   707  		}
   708  		if volID := filesystem.Volume().Id(); volID != "" && !allVolumes.Contains(volID) {
   709  			return errors.NotValidf("filesystem[%d] referencing unknown volume %q", i, volID)
   710  		}
   711  		for j, attachment := range filesystem.Attachments() {
   712  			if machineID := attachment.Machine().Id(); !allMachineIDs.Contains(machineID) {
   713  				return errors.NotValidf("filesystem[%d].attachment[%d] referencing unknown machine %q", i, j, machineID)
   714  			}
   715  		}
   716  	}
   717  
   718  	return nil
   719  }
   720  
   721  // validateSubnets makes sure that any spaces referenced by subnets exist.
   722  func (m *model) validateSubnets() error {
   723  	spaceNames := set.NewStrings()
   724  	for _, space := range m.Spaces_.Spaces_ {
   725  		spaceNames.Add(space.Name())
   726  	}
   727  	for _, subnet := range m.Subnets_.Subnets_ {
   728  		if subnet.SpaceName() == "" {
   729  			continue
   730  		}
   731  		if !spaceNames.Contains(subnet.SpaceName()) {
   732  			return errors.Errorf("subnet %q references non-existent space %q", subnet.CIDR(), subnet.SpaceName())
   733  		}
   734  	}
   735  
   736  	return nil
   737  }
   738  
   739  func (m *model) machineMaps() (map[string]Machine, map[string]map[string]LinkLayerDevice) {
   740  	machineIDs := make(map[string]Machine)
   741  	for _, machine := range m.Machines_.Machines_ {
   742  		addMachinesToMap(machine, machineIDs)
   743  	}
   744  
   745  	// Build a map of all devices for each machine.
   746  	machineDevices := make(map[string]map[string]LinkLayerDevice)
   747  	for _, device := range m.LinkLayerDevices_.LinkLayerDevices_ {
   748  		_, ok := machineDevices[device.MachineID()]
   749  		if !ok {
   750  			machineDevices[device.MachineID()] = make(map[string]LinkLayerDevice)
   751  		}
   752  		machineDevices[device.MachineID()][device.Name()] = device
   753  	}
   754  	return machineIDs, machineDevices
   755  }
   756  
   757  func addMachinesToMap(machine Machine, machineIDs map[string]Machine) {
   758  	machineIDs[machine.Id()] = machine
   759  	for _, container := range machine.Containers() {
   760  		addMachinesToMap(container, machineIDs)
   761  	}
   762  }
   763  
   764  // validateAddresses makes sure that the machine and device referenced by IP
   765  // addresses exist.
   766  func (m *model) validateAddresses() error {
   767  	machineIDs, machineDevices := m.machineMaps()
   768  	for _, addr := range m.IPAddresses_.IPAddresses_ {
   769  		_, ok := machineIDs[addr.MachineID()]
   770  		if !ok {
   771  			return errors.Errorf("ip address %q references non-existent machine %q", addr.Value(), addr.MachineID())
   772  		}
   773  		_, ok = machineDevices[addr.MachineID()][addr.DeviceName()]
   774  		if !ok {
   775  			return errors.Errorf("ip address %q references non-existent device %q", addr.Value(), addr.DeviceName())
   776  		}
   777  		if ip := net.ParseIP(addr.Value()); ip == nil {
   778  			return errors.Errorf("ip address has invalid value %q", addr.Value())
   779  		}
   780  		if addr.SubnetCIDR() == "" {
   781  			return errors.Errorf("ip address %q has empty subnet CIDR", addr.Value())
   782  		}
   783  		if _, _, err := net.ParseCIDR(addr.SubnetCIDR()); err != nil {
   784  			return errors.Errorf("ip address %q has invalid subnet CIDR %q", addr.Value(), addr.SubnetCIDR())
   785  		}
   786  
   787  		if addr.GatewayAddress() != "" {
   788  			if ip := net.ParseIP(addr.GatewayAddress()); ip == nil {
   789  				return errors.Errorf("ip address %q has invalid gateway address %q", addr.Value(), addr.GatewayAddress())
   790  			}
   791  		}
   792  	}
   793  	return nil
   794  }
   795  
   796  // validateLinkLayerDevices makes sure that any machines referenced by link
   797  // layer devices exist.
   798  func (m *model) validateLinkLayerDevices() error {
   799  	machineIDs, machineDevices := m.machineMaps()
   800  	for _, device := range m.LinkLayerDevices_.LinkLayerDevices_ {
   801  		machine, ok := machineIDs[device.MachineID()]
   802  		if !ok {
   803  			return errors.Errorf("device %q references non-existent machine %q", device.Name(), device.MachineID())
   804  		}
   805  		if device.Name() == "" {
   806  			return errors.Errorf("device has empty name: %#v", device)
   807  		}
   808  		if device.MACAddress() != "" {
   809  			if _, err := net.ParseMAC(device.MACAddress()); err != nil {
   810  				return errors.Errorf("device %q has invalid MACAddress %q", device.Name(), device.MACAddress())
   811  			}
   812  		}
   813  		if device.ParentName() == "" {
   814  			continue
   815  		}
   816  		hostMachineID, parentDeviceName, canBeGlobalKey := parseLinkLayerDeviceGlobalKey(device.ParentName())
   817  		if !canBeGlobalKey {
   818  			hostMachineID = device.MachineID()
   819  			parentDeviceName = device.ParentName()
   820  		}
   821  		parentDevice, ok := machineDevices[hostMachineID][parentDeviceName]
   822  		if !ok {
   823  			return errors.Errorf("device %q has non-existent parent %q", device.Name(), parentDeviceName)
   824  		}
   825  		if !canBeGlobalKey {
   826  			if device.Name() == parentDeviceName {
   827  				return errors.Errorf("device %q is its own parent", device.Name())
   828  			}
   829  			continue
   830  		}
   831  		// The device is on a container.
   832  		if parentDevice.Type() != "bridge" {
   833  			return errors.Errorf("device %q on a container but not a bridge", device.Name())
   834  		}
   835  		parentId := parentId(machine.Id())
   836  		if parentId == "" {
   837  			return errors.Errorf("ParentName %q for non-container machine %q", device.ParentName(), machine.Id())
   838  		}
   839  		if parentDevice.MachineID() != parentId {
   840  			return errors.Errorf("parent machine of device %q not host machine %q", device.Name(), parentId)
   841  		}
   842  	}
   843  	return nil
   844  }
   845  
   846  // validateRelations makes sure that for each endpoint in each relation there
   847  // are settings for all units of that application for that endpoint.
   848  func (m *model) validateRelations() error {
   849  	for _, relation := range m.Relations_.Relations_ {
   850  		for _, ep := range relation.Endpoints_.Endpoints_ {
   851  			// Check application exists.
   852  			application := m.application(ep.ApplicationName())
   853  			if application == nil {
   854  				return errors.Errorf("unknown application %q for relation id %d", ep.ApplicationName(), relation.Id())
   855  			}
   856  			// Check that all units have settings.
   857  			applicationUnits := application.unitNames()
   858  			epUnits := ep.unitNames()
   859  			if missingSettings := applicationUnits.Difference(epUnits); len(missingSettings) > 0 {
   860  				return errors.Errorf("missing relation settings for units %s in relation %d", missingSettings.SortedValues(), relation.Id())
   861  			}
   862  			if extraSettings := epUnits.Difference(applicationUnits); len(extraSettings) > 0 {
   863  				return errors.Errorf("settings for unknown units %s in relation %d", extraSettings.SortedValues(), relation.Id())
   864  			}
   865  		}
   866  	}
   867  	return nil
   868  }
   869  
   870  // importModel constructs a new Model from a map that in normal usage situations
   871  // will be the result of interpreting a large YAML document.
   872  //
   873  // This method is a package internal serialisation method.
   874  func importModel(source map[string]interface{}) (*model, error) {
   875  	version, err := getVersion(source)
   876  	if err != nil {
   877  		return nil, errors.Trace(err)
   878  	}
   879  
   880  	importFunc, ok := modelDeserializationFuncs[version]
   881  	if !ok {
   882  		return nil, errors.NotValidf("version %d", version)
   883  	}
   884  
   885  	return importFunc(source)
   886  }
   887  
   888  type modelDeserializationFunc func(map[string]interface{}) (*model, error)
   889  
   890  var modelDeserializationFuncs = map[int]modelDeserializationFunc{
   891  	1: importModelV1,
   892  }
   893  
   894  func importModelV1(source map[string]interface{}) (*model, error) {
   895  	fields := schema.Fields{
   896  		"owner":                schema.String(),
   897  		"cloud":                schema.String(),
   898  		"cloud-region":         schema.String(),
   899  		"config":               schema.StringMap(schema.Any()),
   900  		"latest-tools":         schema.String(),
   901  		"blocks":               schema.StringMap(schema.String()),
   902  		"users":                schema.StringMap(schema.Any()),
   903  		"machines":             schema.StringMap(schema.Any()),
   904  		"applications":         schema.StringMap(schema.Any()),
   905  		"relations":            schema.StringMap(schema.Any()),
   906  		"ssh-host-keys":        schema.StringMap(schema.Any()),
   907  		"cloud-image-metadata": schema.StringMap(schema.Any()),
   908  		"actions":              schema.StringMap(schema.Any()),
   909  		"ip-addresses":         schema.StringMap(schema.Any()),
   910  		"spaces":               schema.StringMap(schema.Any()),
   911  		"subnets":              schema.StringMap(schema.Any()),
   912  		"link-layer-devices":   schema.StringMap(schema.Any()),
   913  		"volumes":              schema.StringMap(schema.Any()),
   914  		"filesystems":          schema.StringMap(schema.Any()),
   915  		"storages":             schema.StringMap(schema.Any()),
   916  		"storage-pools":        schema.StringMap(schema.Any()),
   917  		"sequences":            schema.StringMap(schema.Int()),
   918  	}
   919  	// Some values don't have to be there.
   920  	defaults := schema.Defaults{
   921  		"latest-tools": schema.Omit,
   922  		"blocks":       schema.Omit,
   923  		"cloud-region": schema.Omit,
   924  	}
   925  	addAnnotationSchema(fields, defaults)
   926  	addConstraintsSchema(fields, defaults)
   927  	checker := schema.FieldMap(fields, defaults)
   928  
   929  	coerced, err := checker.Coerce(source, nil)
   930  	if err != nil {
   931  		return nil, errors.Annotatef(err, "model v1 schema check failed")
   932  	}
   933  	valid := coerced.(map[string]interface{})
   934  	// From here we know that the map returned from the schema coercion
   935  	// contains fields of the right type.
   936  
   937  	result := &model{
   938  		Version:    1,
   939  		Owner_:     valid["owner"].(string),
   940  		Config_:    valid["config"].(map[string]interface{}),
   941  		Sequences_: make(map[string]int),
   942  		Blocks_:    convertToStringMap(valid["blocks"]),
   943  		Cloud_:     valid["cloud"].(string),
   944  	}
   945  	result.importAnnotations(valid)
   946  	sequences := valid["sequences"].(map[string]interface{})
   947  	for key, value := range sequences {
   948  		result.SetSequence(key, int(value.(int64)))
   949  	}
   950  
   951  	if constraintsMap, ok := valid["constraints"]; ok {
   952  		constraints, err := importConstraints(constraintsMap.(map[string]interface{}))
   953  		if err != nil {
   954  			return nil, errors.Trace(err)
   955  		}
   956  		result.Constraints_ = constraints
   957  	}
   958  
   959  	if availableTools, ok := valid["latest-tools"]; ok {
   960  		num, err := version.Parse(availableTools.(string))
   961  		if err != nil {
   962  			return nil, errors.Trace(err)
   963  		}
   964  		result.LatestToolsVersion_ = num
   965  	}
   966  
   967  	if region, ok := valid["cloud-region"]; ok {
   968  		result.CloudRegion_ = region.(string)
   969  	}
   970  
   971  	if credential, ok := valid["cloud-credential"]; ok {
   972  		result.CloudCredential_ = credential.(string)
   973  	}
   974  
   975  	userMap := valid["users"].(map[string]interface{})
   976  	users, err := importUsers(userMap)
   977  	if err != nil {
   978  		return nil, errors.Annotate(err, "users")
   979  	}
   980  	result.setUsers(users)
   981  
   982  	machineMap := valid["machines"].(map[string]interface{})
   983  	machines, err := importMachines(machineMap)
   984  	if err != nil {
   985  		return nil, errors.Annotate(err, "machines")
   986  	}
   987  	result.setMachines(machines)
   988  
   989  	applicationMap := valid["applications"].(map[string]interface{})
   990  	applications, err := importApplications(applicationMap)
   991  	if err != nil {
   992  		return nil, errors.Annotate(err, "applications")
   993  	}
   994  	result.setApplications(applications)
   995  
   996  	relationMap := valid["relations"].(map[string]interface{})
   997  	relations, err := importRelations(relationMap)
   998  	if err != nil {
   999  		return nil, errors.Annotate(err, "relations")
  1000  	}
  1001  	result.setRelations(relations)
  1002  
  1003  	spaceMap := valid["spaces"].(map[string]interface{})
  1004  	spaces, err := importSpaces(spaceMap)
  1005  	if err != nil {
  1006  		return nil, errors.Annotate(err, "spaces")
  1007  	}
  1008  	result.setSpaces(spaces)
  1009  
  1010  	deviceMap := valid["link-layer-devices"].(map[string]interface{})
  1011  	devices, err := importLinkLayerDevices(deviceMap)
  1012  	if err != nil {
  1013  		return nil, errors.Annotate(err, "link-layer-devices")
  1014  	}
  1015  	result.setLinkLayerDevices(devices)
  1016  
  1017  	subnetsMap := valid["subnets"].(map[string]interface{})
  1018  	subnets, err := importSubnets(subnetsMap)
  1019  	if err != nil {
  1020  		return nil, errors.Annotate(err, "subnets")
  1021  	}
  1022  	result.setSubnets(subnets)
  1023  
  1024  	addressMap := valid["ip-addresses"].(map[string]interface{})
  1025  	addresses, err := importIPAddresses(addressMap)
  1026  	if err != nil {
  1027  		return nil, errors.Annotate(err, "ip-addresses")
  1028  	}
  1029  	result.setIPAddresses(addresses)
  1030  
  1031  	sshHostKeyMap := valid["ssh-host-keys"].(map[string]interface{})
  1032  	hostKeys, err := importSSHHostKeys(sshHostKeyMap)
  1033  	if err != nil {
  1034  		return nil, errors.Annotate(err, "ssh-host-keys")
  1035  	}
  1036  	result.setSSHHostKeys(hostKeys)
  1037  
  1038  	cloudimagemetadataMap := valid["cloud-image-metadata"].(map[string]interface{})
  1039  	cloudimagemetadata, err := importCloudImageMetadata(cloudimagemetadataMap)
  1040  	if err != nil {
  1041  		return nil, errors.Annotate(err, "cloud-image-metadata")
  1042  	}
  1043  	result.setCloudImageMetadatas(cloudimagemetadata)
  1044  
  1045  	actionsMap := valid["actions"].(map[string]interface{})
  1046  	actions, err := importActions(actionsMap)
  1047  	if err != nil {
  1048  		return nil, errors.Annotate(err, "actions")
  1049  	}
  1050  	result.setActions(actions)
  1051  
  1052  	volumes, err := importVolumes(valid["volumes"].(map[string]interface{}))
  1053  	if err != nil {
  1054  		return nil, errors.Annotate(err, "volumes")
  1055  	}
  1056  	result.setVolumes(volumes)
  1057  
  1058  	filesystems, err := importFilesystems(valid["filesystems"].(map[string]interface{}))
  1059  	if err != nil {
  1060  		return nil, errors.Annotate(err, "filesystems")
  1061  	}
  1062  	result.setFilesystems(filesystems)
  1063  
  1064  	storages, err := importStorages(valid["storages"].(map[string]interface{}))
  1065  	if err != nil {
  1066  		return nil, errors.Annotate(err, "storages")
  1067  	}
  1068  	result.setStorages(storages)
  1069  
  1070  	pools, err := importStoragePools(valid["storage-pools"].(map[string]interface{}))
  1071  	if err != nil {
  1072  		return nil, errors.Annotate(err, "storage-pools")
  1073  	}
  1074  	result.setStoragePools(pools)
  1075  
  1076  	return result, nil
  1077  }