func (m Meta) Check(format Format, reasons ...FormatSelectionReason) error {
	switch format {
	case FormatV1:
		err := m.checkV1(reasons)
		if err != nil {
			return errors.Trace(err)
		}
	case FormatV2:
		err := m.checkV2(reasons)
		if err != nil {
			return errors.Trace(err)
		}
	default:
		return errors.Errorf("unknown format %v", format)
	}

	// Check for duplicate or forbidden relation names or interfaces.
	names := make(map[string]bool)
	checkRelations := func(src map[string]Relation, role RelationRole) error {
		for name, rel := range src {
			if rel.Name != name {
				return errors.Errorf("charm %q has mismatched relation name %q; expected %q", m.Name, rel.Name, name)
			}
			if rel.Role != role {
				return errors.Errorf("charm %q has mismatched role %q; expected %q", m.Name, rel.Role, role)
			}
			// Container-scoped require relations on subordinates are allowed
			// to use the otherwise-reserved juju-* namespace.
			if !m.Subordinate || role != RoleRequirer || rel.Scope != ScopeContainer {
				if reserved, _ := reservedName(name); reserved {
					return errors.Errorf("charm %q using a reserved relation name: %q", m.Name, name)
				}
			}
			if role != RoleRequirer {
				if reserved, _ := reservedName(rel.Interface); reserved {
					return errors.Errorf("charm %q relation %q using a reserved interface: %q", m.Name, name, rel.Interface)
				}
			}
			if names[name] {
				return errors.Errorf("charm %q using a duplicated relation name: %q", m.Name, name)
			}
			names[name] = true
		}
		return nil
	}
	if err := checkRelations(m.Provides, RoleProvider); err != nil {
		return err
	}
	if err := checkRelations(m.Requires, RoleRequirer); err != nil {
		return err
	}
	if err := checkRelations(m.Peers, RolePeer); err != nil {
		return err
	}

	if err := validateMetaExtraBindings(m); err != nil {
		return errors.Errorf("charm %q has invalid extra bindings: %v", m.Name, err)
	}

	// Subordinate charms must have at least one relation that
	// has container scope, otherwise they can't relate to the
	// principal.
	if m.Subordinate {
		valid := false
		if m.Requires != nil {
			for _, relationData := range m.Requires {
				if relationData.Scope == ScopeContainer {
					valid = true
					break
				}
			}
		}
		if !valid {
			return errors.Errorf("subordinate charm %q lacks \"requires\" relation with container scope", m.Name)
		}
	}

	for _, series := range m.Series {
		if !IsValidSeries(series) {
			return errors.Errorf("charm %q declares invalid series: %q", m.Name, series)
		}
	}

	names = make(map[string]bool)
	for name, store := range m.Storage {
		if store.Location != "" && store.Type != StorageFilesystem {
			return errors.Errorf(`charm %q storage %q: location may not be specified for "type: %s"`, m.Name, name, store.Type)
		}
		if store.Type == "" {
			return errors.Errorf("charm %q storage %q: type must be specified", m.Name, name)
		}
		if store.CountMin < 0 {
			return errors.Errorf("charm %q storage %q: invalid minimum count %d", m.Name, name, store.CountMin)
		}
		if store.CountMax == 0 || store.CountMax < -1 {
			return errors.Errorf("charm %q storage %q: invalid maximum count %d", m.Name, name, store.CountMax)
		}
		if names[name] {
			return errors.Errorf("charm %q storage %q: duplicated storage name", m.Name, name)
		}
		names[name] = true
	}

	names = make(map[string]bool)
	for name, device := range m.Devices {
		if device.Type == "" {
			return errors.Errorf("charm %q device %q: type must be specified", m.Name, name)
		}
		if device.CountMax >= 0 && device.CountMin >= 0 && device.CountMin > device.CountMax {
			return errors.Errorf(
				"charm %q device %q: maximum count %d can not be smaller than minimum count %d",
				m.Name, name, device.CountMax, device.CountMin)
		}
		if names[name] {
			return errors.Errorf("charm %q device %q: duplicated device name", m.Name, name)
		}
		names[name] = true
	}

	for name, payloadClass := range m.PayloadClasses {
		if payloadClass.Name != name {
			return errors.Errorf("mismatch on payload class name (%q != %q)", payloadClass.Name, name)
		}
		if err := payloadClass.Validate(); err != nil {
			return err
		}
	}

	if err := validateMetaResources(m.Resources); err != nil {
		return err
	}

	for _, term := range m.Terms {
		if _, terr := ParseTerm(term); terr != nil {
			return errors.Trace(terr)
		}
	}

	return nil
}
// Check checks that the metadata is well-formed.
Check checks that the metadata is well-formed.
// Check checks that the metadata is well - formed .
func (m Meta) Check(format Format, reasons ...FormatSelectionReason) error {
	switch format {
	case FormatV1:
		err := m.checkV1(reasons)
		if err != nil {
			return errors.Trace(err)
		}
	case FormatV2:
		err := m.checkV2(reasons)
		if err != nil {
			return errors.Trace(err)
		}
	default:
		return errors.Errorf("unknown format %v", format)
	}
	names := make(map[string]bool)
	checkRelations := func(src map[string]Relation, role RelationRole) error {
		for name, rel := range src {
			if rel.Name != name {
				return errors.Errorf("charm %q has mismatched relation name %q; expected %q", m.Name, rel.Name, name)
			}
			if rel.Role != role {
				return errors.Errorf("charm %q has mismatched role %q; expected %q", m.Name, rel.Role, role)
			}
			if !m.Subordinate || role != RoleRequirer || rel.Scope != ScopeContainer {
				if reserved, _ := reservedName(name); reserved {
					return errors.Errorf("charm %q using a reserved relation name: %q", m.Name, name)
				}
			}
			if role != RoleRequirer {
				if reserved, _ := reservedName(rel.Interface); reserved {
					return errors.Errorf("charm %q relation %q using a reserved interface: %q", m.Name, name, rel.Interface)
				}
			}
			if names[name] {
				return errors.Errorf("charm %q using a duplicated relation name: %q", m.Name, name)
			}
			names[name] = true
		}
		return nil
	}
	if err := checkRelations(m.Provides, RoleProvider); err != nil {
		return err
	}
	if err := checkRelations(m.Requires, RoleRequirer); err != nil {
		return err
	}
	if err := checkRelations(m.Peers, RolePeer); err != nil {
		return err
	}
	if err := validateMetaExtraBindings(m); err != nil {
		return errors.Errorf("charm %q has invalid extra bindings: %v", m.Name, err)
	}
	if m.Subordinate {
		valid := false
		if m.Requires != nil {
			for _, relationData := range m.Requires {
				if relationData.Scope == ScopeContainer {
					valid = true
					break
				}
			}
		}
		if !valid {
			return errors.Errorf("subordinate charm %q lacks \"requires\" relation with container scope", m.Name)
		}
	}
	for _, series := range m.Series {
		if !IsValidSeries(series) {
			return errors.Errorf("charm %q declares invalid series: %q", m.Name, series)
		}
	}
	names = make(map[string]bool)
	for name, store := range m.Storage {
		if store.Location != "" && store.Type != StorageFilesystem {
			return errors.Errorf(`charm %q storage %q: location may not be specified for "type: %s"`, m.Name, name, store.Type)
		}
		if store.Type == "" {
			return errors.Errorf("charm %q storage %q: type must be specified", m.Name, name)
		}
		if store.CountMin < 0 {
			return errors.Errorf("charm %q storage %q: invalid minimum count %d", m.Name, name, store.CountMin)
		}
		if store.CountMax == 0 || store.CountMax < -1 {
			return errors.Errorf("charm %q storage %q: invalid maximum count %d", m.Name, name, store.CountMax)
		}
		if names[name] {
			return errors.Errorf("charm %q storage %q: duplicated storage name", m.Name, name)
		}
		names[name] = true
	}
	names = make(map[string]bool)
	for name, device := range m.Devices {
		if device.Type == "" {
			return errors.Errorf("charm %q device %q: type must be specified", m.Name, name)
		}
		if device.CountMax >= 0 && device.CountMin >= 0 && device.CountMin > device.CountMax {
			return errors.Errorf(
				"charm %q device %q: maximum count %d can not be smaller than minimum count %d",
				m.Name, name, device.CountMax, device.CountMin)
		}
		if names[name] {
			return errors.Errorf("charm %q device %q: duplicated device name", m.Name, name)
		}
		names[name] = true
	}
	for name, payloadClass := range m.PayloadClasses {
		if payloadClass.Name != name {
			return errors.Errorf("mismatch on payload class name (%q != %q)", payloadClass.Name, name)
		}
		if err := payloadClass.Validate(); err != nil {
			return err
		}
	}
	if err := validateMetaResources(m.Resources); err != nil {
		return err
	}
	for _, term := range m.Terms {
		if _, terr := ParseTerm(term); terr != nil {
			return errors.Trace(terr)
		}
	}
	return nil
}
func ( m Meta ) Check ( format Format , reasons ... FormatSelectionReason ) error { switch format { case FormatV1 : err := m . checkV1 ( reasons ) if err != nil { return errors . Trace ( err ) } case FormatV2 : err := m . checkV2 ( reasons ) if err != nil { return errors . Trace ( err ) } default : return errors . Errorf ( " " , format ) } names := make ( map [ string ] bool ) checkRelations := func ( src map [ string ] Relation , role RelationRole ) error { for name , rel := range src { if rel . Name != name { return errors . Errorf ( " " , m . Name , rel . Name , name ) } if rel . Role != role { return errors . Errorf ( " " , m . Name , rel . Role , role ) } if ! m . Subordinate || role != RoleRequirer || rel . Scope != ScopeContainer { if reserved , _ := reservedName ( name ) ; reserved { return errors . Errorf ( " " , m . Name , name ) } } if role != RoleRequirer { if reserved , _ := reservedName ( rel . Interface ) ; reserved { return errors . Errorf ( " " , m . Name , name , rel . Interface ) } } if names [ name ] { return errors . Errorf ( " " , m . Name , name ) } names [ name ] = true } return nil } if err := checkRelations ( m . Provides , RoleProvider ) ; err != nil { return err } if err := checkRelations ( m . Requires , RoleRequirer ) ; err != nil { return err } if err := checkRelations ( m . Peers , RolePeer ) ; err != nil { return err } if err := validateMetaExtraBindings ( m ) ; err != nil { return errors . Errorf ( " " , m . Name , err ) } if m . Subordinate { valid := false if m . Requires != nil { for _ , relationData := range m . Requires { if relationData . Scope == ScopeContainer { valid = true break } } } if ! valid { return errors . Errorf ( " \" \" " , m . Name ) } } for _ , series := range m . Series { if ! IsValidSeries ( series ) { return errors . Errorf ( " " , m . Name , series ) } } names = make ( map [ string ] bool ) for name , store := range m . Storage { if store . Location != " " && store . Type != StorageFilesystem { return errors . Errorf ( `charm %q storage %q: location may not be specified for "type: %s"` , m . Name , name , store . Type ) } if store . Type == " " { return errors . Errorf ( " " , m . Name , name ) } if store . CountMin < 0 { return errors . Errorf ( " " , m . Name , name , store . CountMin ) } if store . CountMax == 0 || store . CountMax < - 1 { return errors . Errorf ( " " , m . Name , name , store . CountMax ) } if names [ name ] { return errors . Errorf ( " " , m . Name , name ) } names [ name ] = true } names = make ( map [ string ] bool ) for name , device := range m . Devices { if device . Type == " " { return errors . Errorf ( " " , m . Name , name ) } if device . CountMax >= 0 && device . CountMin >= 0 && device . CountMin > device . CountMax { return errors . Errorf ( " " , m . Name , name , device . CountMax , device . CountMin ) } if names [ name ] { return errors . Errorf ( " " , m . Name , name ) } names [ name ] = true } for name , payloadClass := range m . PayloadClasses { if payloadClass . Name != name { return errors . Errorf ( " " , payloadClass . Name , name ) } if err := payloadClass . Validate ( ) ; err != nil { return err } } if err := validateMetaResources ( m . Resources ) ; err != nil { return err } for _ , term := range m . Terms { if _ , terr := ParseTerm ( term ) ; terr != nil { return errors . Trace ( terr ) } } return nil }
Check checks that the metadata is well-formed.
Check checks that the metadata is well - formed .
// Check for duplicate or forbidden relation names or interfaces. // Container-scoped require relations on subordinates are allowed // to use the otherwise-reserved juju-* namespace. // Subordinate charms must have at least one relation that // has container scope, otherwise they can't relate to the // principal.