コード例 #1
0
ファイル: controller.go プロジェクト: voidspace/gomaasapi
func parseAllocateConstraintsResponse(source interface{}, machine *machine) (ConstraintMatches, error) {
	var empty ConstraintMatches
	matchFields := schema.Fields{
		"storage":    schema.StringMap(schema.ForceInt()),
		"interfaces": schema.StringMap(schema.ForceInt()),
	}
	matchDefaults := schema.Defaults{
		"storage":    schema.Omit,
		"interfaces": schema.Omit,
	}
	fields := schema.Fields{
		"constraints_by_type": schema.FieldMap(matchFields, matchDefaults),
	}
	checker := schema.FieldMap(fields, nil) // no defaults
	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return empty, WrapWithDeserializationError(err, "allocation constraints response schema check failed")
	}
	valid := coerced.(map[string]interface{})
	constraintsMap := valid["constraints_by_type"].(map[string]interface{})
	result := ConstraintMatches{
		Interfaces: make(map[string]Interface),
		Storage:    make(map[string]BlockDevice),
	}

	if interfaceMatches, found := constraintsMap["interfaces"]; found {
		for label, value := range interfaceMatches.(map[string]interface{}) {
			id := value.(int)
			iface := machine.Interface(id)
			if iface == nil {
				return empty, NewDeserializationError("constraint match interface %q: %d does not match an interface for the machine", label, id)
			}
			result.Interfaces[label] = iface
		}
	}

	if storageMatches, found := constraintsMap["storage"]; found {
		for label, value := range storageMatches.(map[string]interface{}) {
			id := value.(int)
			blockDevice := machine.PhysicalBlockDevice(id)
			if blockDevice == nil {
				return empty, NewDeserializationError("constraint match storage %q: %d does not match a physical block device for the machine", label, id)
			}
			result.Storage[label] = blockDevice
		}
	}
	return result, nil
}
コード例 #2
0
ファイル: action.go プロジェクト: bac/juju
func importActionV1(source map[string]interface{}) (*action, error) {
	fields := schema.Fields{
		"receiver":   schema.String(),
		"name":       schema.String(),
		"parameters": schema.StringMap(schema.Any()),
		"enqueued":   schema.Time(),
		"started":    schema.Time(),
		"completed":  schema.Time(),
		"status":     schema.String(),
		"message":    schema.String(),
		"results":    schema.StringMap(schema.Any()),
		"id":         schema.String(),
	}
	// Some values don't have to be there.
	defaults := schema.Defaults{
		"started":   time.Time{},
		"completed": time.Time{},
	}
	checker := schema.FieldMap(fields, defaults)

	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, errors.Annotatef(err, "action v1 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	action := &action{
		Id_:         valid["id"].(string),
		Receiver_:   valid["receiver"].(string),
		Name_:       valid["name"].(string),
		Status_:     valid["status"].(string),
		Message_:    valid["message"].(string),
		Parameters_: valid["parameters"].(map[string]interface{}),
		Enqueued_:   valid["enqueued"].(time.Time).UTC(),
		Results_:    valid["results"].(map[string]interface{}),
	}

	started := valid["started"].(time.Time)
	if !started.IsZero() {
		started = started.UTC()
		action.Started_ = &started
	}
	completed := valid["completed"].(time.Time)
	if !started.IsZero() {
		completed = completed.UTC()
		action.Completed_ = &completed
	}
	return action, nil
}
コード例 #3
0
ファイル: status.go プロジェクト: AlexisBruemmer/juju
func importStatusV1(source map[string]interface{}) (StatusPoint_, error) {
	fields := schema.Fields{
		"value":   schema.String(),
		"message": schema.String(),
		"data":    schema.StringMap(schema.Any()),
		"updated": schema.Time(),
	}
	// Some values don't have to be there.
	defaults := schema.Defaults{
		"message": "",
		"data":    schema.Omit,
	}
	checker := schema.FieldMap(fields, defaults)

	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return StatusPoint_{}, errors.Annotatef(err, "status v1 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.

	var data map[string]interface{}
	if sourceData, set := valid["data"]; set {
		data = sourceData.(map[string]interface{})
	}
	return StatusPoint_{
		Value_:   valid["value"].(string),
		Message_: valid["message"].(string),
		Data_:    data,
		Updated_: valid["updated"].(time.Time),
	}, nil
}
コード例 #4
0
ファイル: schema_test.go プロジェクト: howbazaar/schema
func (s *S) TestStringified(c *gc.C) {
	s.sch = schema.Stringified()

	out, err := s.sch.Coerce(true, aPath)
	c.Assert(err, gc.IsNil)
	c.Check(out, gc.Equals, "true")

	out, err = s.sch.Coerce(10, aPath)
	c.Assert(err, gc.IsNil)
	c.Check(out, gc.Equals, "10")

	out, err = s.sch.Coerce(1.1, aPath)
	c.Assert(err, gc.IsNil)
	c.Check(out, gc.Equals, "1.1")

	out, err = s.sch.Coerce("spam", aPath)
	c.Assert(err, gc.IsNil)
	c.Check(out, gc.Equals, "spam")

	_, err = s.sch.Coerce(map[string]string{}, aPath)
	c.Check(err, gc.ErrorMatches, ".* unexpected value .*")

	_, err = s.sch.Coerce([]string{}, aPath)
	c.Check(err, gc.ErrorMatches, ".* unexpected value .*")

	s.sch = schema.Stringified(schema.StringMap(schema.String()))

	out, err = s.sch.Coerce(map[string]string{"a": "b"}, aPath)
	c.Assert(err, gc.IsNil)
	c.Check(out, gc.Equals, `map[string]string{"a":"b"}`)
}
コード例 #5
0
ファイル: ports.go プロジェクト: bac/juju
func importOpenedPortsV1(source map[string]interface{}) (*openedPorts, error) {
	fields := schema.Fields{
		"subnet-id":    schema.String(),
		"opened-ports": schema.StringMap(schema.Any()),
	}

	checker := schema.FieldMap(fields, nil) // no defaults

	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, errors.Annotatef(err, "opened-ports v1 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.

	ports, err := importPortRanges(valid["opened-ports"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Trace(err)
	}
	result := &openedPorts{
		SubnetID_: valid["subnet-id"].(string),
	}
	result.setOpenedPorts(ports)
	return result, nil
}
コード例 #6
0
ファイル: serialization.go プロジェクト: bac/juju
func versionedEmbeddedChecker(name string) schema.Checker {
	fields := schema.Fields{
		"version": schema.Int(),
	}
	fields[name] = schema.StringMap(schema.Any())
	return schema.FieldMap(fields, nil) // no defaults
}
コード例 #7
0
ファイル: space.go プロジェクト: voidspace/gomaasapi
func space_2_0(source map[string]interface{}) (*space, error) {
	fields := schema.Fields{
		"resource_uri": schema.String(),
		"id":           schema.ForceInt(),
		"name":         schema.String(),
		"subnets":      schema.List(schema.StringMap(schema.Any())),
	}
	checker := schema.FieldMap(fields, nil) // no defaults
	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, errors.Annotatef(err, "space 2.0 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.

	subnets, err := readSubnetList(valid["subnets"].([]interface{}), subnet_2_0)
	if err != nil {
		return nil, errors.Trace(err)
	}

	result := &space{
		resourceURI: valid["resource_uri"].(string),
		id:          valid["id"].(int),
		name:        valid["name"].(string),
		subnets:     subnets,
	}
	return result, nil
}
コード例 #8
0
ファイル: relation.go プロジェクト: AlexisBruemmer/juju
func importRelationV1(source map[string]interface{}) (*relation, error) {
	fields := schema.Fields{
		"id":        schema.Int(),
		"key":       schema.String(),
		"endpoints": schema.StringMap(schema.Any()),
	}

	checker := schema.FieldMap(fields, nil) // no defaults

	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, errors.Annotatef(err, "relation v1 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.
	result := &relation{
		Id_:  int(valid["id"].(int64)),
		Key_: valid["key"].(string),
	}

	endpoints, err := importEndpoints(valid["endpoints"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Trace(err)
	}
	result.setEndpoints(endpoints)

	return result, nil
}
コード例 #9
0
ファイル: schema_test.go プロジェクト: howbazaar/schema
func (s *S) TestStringMap(c *gc.C) {
	s.sch = schema.StringMap(schema.Int())
	out, err := s.sch.Coerce(map[string]interface{}{"a": 1, "b": int8(2)}, aPath)
	c.Assert(err, gc.IsNil)
	c.Assert(out, gc.DeepEquals, map[string]interface{}{"a": int64(1), "b": int64(2)})

	out, err = s.sch.Coerce(42, aPath)
	c.Assert(out, gc.IsNil)
	c.Assert(err, gc.ErrorMatches, "<path>: expected map, got int\\(42\\)")

	out, err = s.sch.Coerce(nil, aPath)
	c.Assert(out, gc.IsNil)
	c.Assert(err, gc.ErrorMatches, "<path>: expected map, got nothing")

	out, err = s.sch.Coerce(map[int]int{1: 1}, aPath)
	c.Assert(out, gc.IsNil)
	c.Assert(err, gc.ErrorMatches, "<path>: expected string, got int\\(1\\)")

	out, err = s.sch.Coerce(map[string]bool{"a": true}, aPath)
	c.Assert(out, gc.IsNil)
	c.Assert(err, gc.ErrorMatches, `<path>\.a: expected int, got bool\(true\)`)

	// First path entry shouldn't have dots in an error message.
	out, err = s.sch.Coerce(map[string]bool{"a": true}, nil)
	c.Assert(out, gc.IsNil)
	c.Assert(err, gc.ErrorMatches, `a: expected int, got bool\(true\)`)
}
コード例 #10
0
ファイル: device.go プロジェクト: voidspace/gomaasapi
func device_2_0(source map[string]interface{}) (*device, error) {
	fields := schema.Fields{
		"resource_uri": schema.String(),

		"system_id": schema.String(),
		"hostname":  schema.String(),
		"fqdn":      schema.String(),
		"parent":    schema.String(),
		"owner":     schema.String(),

		"ip_addresses":  schema.List(schema.String()),
		"interface_set": schema.List(schema.StringMap(schema.Any())),
		"zone":          schema.StringMap(schema.Any()),
	}
	checker := schema.FieldMap(fields, nil) // no defaults
	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, WrapWithDeserializationError(err, "device 2.0 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.

	interfaceSet, err := readInterfaceList(valid["interface_set"].([]interface{}), interface_2_0)
	if err != nil {
		return nil, errors.Trace(err)
	}
	zone, err := zone_2_0(valid["zone"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Trace(err)
	}

	result := &device{
		resourceURI: valid["resource_uri"].(string),

		systemID: valid["system_id"].(string),
		hostname: valid["hostname"].(string),
		fqdn:     valid["fqdn"].(string),
		parent:   valid["parent"].(string),
		owner:    valid["owner"].(string),

		ipAddresses:  convertToStringSlice(valid["ip_addresses"]),
		interfaceSet: interfaceSet,
		zone:         zone,
	}
	return result, nil
}
コード例 #11
0
ファイル: serialization.go プロジェクト: bac/juju
func versionedChecker(name string) schema.Checker {
	fields := schema.Fields{
		"version": schema.Int(),
	}
	if name != "" {
		fields[name] = schema.List(schema.StringMap(schema.Any()))
	}
	return schema.FieldMap(fields, nil) // no defaults
}
コード例 #12
0
ファイル: relation.go プロジェクト: AlexisBruemmer/juju
func importEndpointV1(source map[string]interface{}) (*endpoint, error) {
	fields := schema.Fields{
		"service-name":  schema.String(),
		"name":          schema.String(),
		"role":          schema.String(),
		"interface":     schema.String(),
		"optional":      schema.Bool(),
		"limit":         schema.Int(),
		"scope":         schema.String(),
		"unit-settings": schema.StringMap(schema.StringMap(schema.Any())),
	}

	checker := schema.FieldMap(fields, nil) // No defaults.

	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, errors.Annotatef(err, "endpoint v1 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.

	result := &endpoint{
		ServiceName_:  valid["service-name"].(string),
		Name_:         valid["name"].(string),
		Role_:         valid["role"].(string),
		Interface_:    valid["interface"].(string),
		Optional_:     valid["optional"].(bool),
		Limit_:        int(valid["limit"].(int64)),
		Scope_:        valid["scope"].(string),
		UnitSettings_: make(map[string]map[string]interface{}),
	}

	for unitname, settings := range valid["unit-settings"].(map[string]interface{}) {
		result.UnitSettings_[unitname] = settings.(map[string]interface{})
	}

	return result, nil
}
コード例 #13
0
ファイル: machine.go プロジェクト: voidspace/gomaasapi
func readMachines(controllerVersion version.Number, source interface{}) ([]*machine, error) {
	readFunc, err := getMachineDeserializationFunc(controllerVersion)
	if err != nil {
		return nil, errors.Trace(err)
	}

	checker := schema.List(schema.StringMap(schema.Any()))
	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, WrapWithDeserializationError(err, "machine base schema check failed")
	}
	valid := coerced.([]interface{})
	return readMachineList(valid, readFunc)
}
コード例 #14
0
ファイル: file.go プロジェクト: voidspace/gomaasapi
func readFile(controllerVersion version.Number, source interface{}) (*file, error) {
	readFunc, err := getFileDeserializationFunc(controllerVersion)
	if err != nil {
		return nil, errors.Trace(err)
	}

	checker := schema.StringMap(schema.Any())
	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, WrapWithDeserializationError(err, "file base schema check failed")
	}
	valid := coerced.(map[string]interface{})
	return readFunc(valid)
}
コード例 #15
0
ファイル: blockdevice.go プロジェクト: voidspace/gomaasapi
func blockdevice_2_0(source map[string]interface{}) (*blockdevice, error) {
	fields := schema.Fields{
		"resource_uri": schema.String(),

		"id":       schema.ForceInt(),
		"name":     schema.String(),
		"model":    schema.String(),
		"path":     schema.String(),
		"used_for": schema.String(),
		"tags":     schema.List(schema.String()),

		"block_size": schema.ForceUint(),
		"used_size":  schema.ForceUint(),
		"size":       schema.ForceUint(),

		"partitions": schema.List(schema.StringMap(schema.Any())),
	}
	checker := schema.FieldMap(fields, nil)
	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, WrapWithDeserializationError(err, "blockdevice 2.0 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.

	partitions, err := readPartitionList(valid["partitions"].([]interface{}), partition_2_0)
	if err != nil {
		return nil, errors.Trace(err)
	}

	result := &blockdevice{
		resourceURI: valid["resource_uri"].(string),

		id:      valid["id"].(int),
		name:    valid["name"].(string),
		model:   valid["model"].(string),
		path:    valid["path"].(string),
		usedFor: valid["used_for"].(string),
		tags:    convertToStringSlice(valid["tags"]),

		blockSize: valid["block_size"].(uint64),
		usedSize:  valid["used_size"].(uint64),
		size:      valid["size"].(uint64),

		partitions: partitions,
	}
	return result, nil
}
コード例 #16
0
ファイル: subnet.go プロジェクト: voidspace/gomaasapi
func subnet_2_0(source map[string]interface{}) (*subnet, error) {
	fields := schema.Fields{
		"resource_uri": schema.String(),
		"id":           schema.ForceInt(),
		"name":         schema.String(),
		"space":        schema.String(),
		"gateway_ip":   schema.OneOf(schema.Nil(""), schema.String()),
		"cidr":         schema.String(),
		"vlan":         schema.StringMap(schema.Any()),
		"dns_servers":  schema.OneOf(schema.Nil(""), schema.List(schema.String())),
	}
	checker := schema.FieldMap(fields, nil) // no defaults
	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, errors.Annotatef(err, "subnet 2.0 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.

	vlan, err := vlan_2_0(valid["vlan"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Trace(err)
	}

	// Since the gateway_ip is optional, we use the two part cast assignment. If
	// the cast fails, then we get the default value we care about, which is the
	// empty string.
	gateway, _ := valid["gateway_ip"].(string)

	result := &subnet{
		resourceURI: valid["resource_uri"].(string),
		id:          valid["id"].(int),
		name:        valid["name"].(string),
		space:       valid["space"].(string),
		vlan:        vlan,
		gateway:     gateway,
		cidr:        valid["cidr"].(string),
		dnsServers:  convertToStringSlice(valid["dns_servers"]),
	}
	return result, nil
}
コード例 #17
0
ファイル: vlan.go プロジェクト: voidspace/gomaasapi
func readVLANs(controllerVersion version.Number, source interface{}) ([]*vlan, error) {
	checker := schema.List(schema.StringMap(schema.Any()))
	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, errors.Annotatef(err, "vlan base schema check failed")
	}
	valid := coerced.([]interface{})

	var deserialisationVersion version.Number
	for v := range vlanDeserializationFuncs {
		if v.Compare(deserialisationVersion) > 0 && v.Compare(controllerVersion) <= 0 {
			deserialisationVersion = v
		}
	}
	if deserialisationVersion == version.Zero {
		return nil, errors.Errorf("no vlan read func for version %s", controllerVersion)
	}
	readFunc := vlanDeserializationFuncs[deserialisationVersion]
	return readVLANList(valid, readFunc)
}
コード例 #18
0
ファイル: bootresource.go プロジェクト: voidspace/gomaasapi
func readBootResources(controllerVersion version.Number, source interface{}) ([]*bootResource, error) {
	checker := schema.List(schema.StringMap(schema.Any()))
	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, WrapWithDeserializationError(err, "boot resource base schema check failed")
	}
	valid := coerced.([]interface{})

	var deserialisationVersion version.Number
	for v := range bootResourceDeserializationFuncs {
		if v.Compare(deserialisationVersion) > 0 && v.Compare(controllerVersion) <= 0 {
			deserialisationVersion = v
		}
	}
	if deserialisationVersion == version.Zero {
		return nil, NewUnsupportedVersionError("no boot resource read func for version %s", controllerVersion)
	}
	readFunc := bootResourceDeserializationFuncs[deserialisationVersion]
	return readBootResourceList(valid, readFunc)
}
コード例 #19
0
ファイル: partition.go プロジェクト: voidspace/gomaasapi
func partition_2_0(source map[string]interface{}) (*partition, error) {
	fields := schema.Fields{
		"resource_uri": schema.String(),

		"id":   schema.ForceInt(),
		"path": schema.String(),
		"uuid": schema.String(),

		"used_for": schema.String(),
		"size":     schema.ForceUint(),

		"filesystem": schema.OneOf(schema.Nil(""), schema.StringMap(schema.Any())),
	}
	checker := schema.FieldMap(fields, nil)
	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, WrapWithDeserializationError(err, "partition 2.0 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.

	var filesystem *filesystem
	if fsSource := valid["filesystem"]; fsSource != nil {
		filesystem, err = filesystem2_0(fsSource.(map[string]interface{}))
		if err != nil {
			return nil, errors.Trace(err)
		}
	}

	result := &partition{
		resourceURI: valid["resource_uri"].(string),
		id:          valid["id"].(int),
		path:        valid["path"].(string),
		uuid:        valid["uuid"].(string),
		usedFor:     valid["used_for"].(string),
		size:        valid["size"].(uint64),
		filesystem:  filesystem,
	}
	return result, nil
}
コード例 #20
0
ファイル: credentials.go プロジェクト: AlexisBruemmer/juju
func (c cloudCredentialChecker) Coerce(v interface{}, path []string) (interface{}, error) {
	out := CloudCredential{
		AuthCredentials: make(map[string]Credential),
	}
	v, err := schema.StringMap(cloudCredentialValueChecker{}).Coerce(v, path)
	if err != nil {
		return nil, err
	}
	mapv := v.(map[string]interface{})
	for k, v := range mapv {
		switch k {
		case "default-region":
			out.DefaultRegion = v.(string)
		case "default-credential":
			out.DefaultCredential = v.(string)
		default:
			out.AuthCredentials[k] = v.(Credential)
		}
	}
	return out, nil
}
コード例 #21
0
ファイル: credentials.go プロジェクト: AlexisBruemmer/juju
func (c cloudCredentialValueChecker) Coerce(v interface{}, path []string) (interface{}, error) {
	field := path[len(path)-1]
	switch field {
	case "default-region", "default-credential":
		return schema.String().Coerce(v, path)
	}
	v, err := schema.StringMap(schema.String()).Coerce(v, path)
	if err != nil {
		return nil, err
	}
	mapv := v.(map[string]interface{})

	authType, _ := mapv["auth-type"].(string)
	if authType == "" {
		return nil, errors.Errorf("%v: missing auth-type", strings.Join(path, ""))
	}

	attrs := make(map[string]string)
	delete(mapv, "auth-type")
	for k, v := range mapv {
		attrs[k] = v.(string)
	}
	return Credential{authType: AuthType(authType), attributes: attrs}, nil
}
コード例 #22
0
ファイル: storagepool.go プロジェクト: bac/juju
func importStoragePoolV1(source map[string]interface{}) (*storagepool, error) {
	fields := schema.Fields{
		"name":       schema.String(),
		"provider":   schema.String(),
		"attributes": schema.StringMap(schema.Any()),
	}

	checker := schema.FieldMap(fields, nil) // no defaults

	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, errors.Annotatef(err, "storagepool v1 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.
	result := &storagepool{
		Name_:       valid["name"].(string),
		Provider_:   valid["provider"].(string),
		Attributes_: valid["attributes"].(map[string]interface{}),
	}

	return result, nil
}
コード例 #23
0
ファイル: fabric.go プロジェクト: voidspace/gomaasapi
func fabric_2_0(source map[string]interface{}) (*fabric, error) {
	fields := schema.Fields{
		"resource_uri": schema.String(),
		"id":           schema.ForceInt(),
		"name":         schema.String(),
		"class_type":   schema.OneOf(schema.Nil(""), schema.String()),
		"vlans":        schema.List(schema.StringMap(schema.Any())),
	}
	checker := schema.FieldMap(fields, nil) // no defaults
	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, errors.Annotatef(err, "fabric 2.0 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.

	vlans, err := readVLANList(valid["vlans"].([]interface{}), vlan_2_0)
	if err != nil {
		return nil, errors.Trace(err)
	}

	// Since the class_type is optional, we use the two part cast assignment. If
	// the cast fails, then we get the default value we care about, which is the
	// empty string.
	classType, _ := valid["class_type"].(string)

	result := &fabric{
		resourceURI: valid["resource_uri"].(string),
		id:          valid["id"].(int),
		name:        valid["name"].(string),
		classType:   classType,
		vlans:       vlans,
	}
	return result, nil
}
コード例 #24
0
ファイル: machine.go プロジェクト: bac/juju
func importMachineV1(source map[string]interface{}) (*machine, error) {
	fields := schema.Fields{
		"id":                   schema.String(),
		"nonce":                schema.String(),
		"password-hash":        schema.String(),
		"placement":            schema.String(),
		"instance":             schema.StringMap(schema.Any()),
		"series":               schema.String(),
		"container-type":       schema.String(),
		"jobs":                 schema.List(schema.String()),
		"status":               schema.StringMap(schema.Any()),
		"supported-containers": schema.List(schema.String()),
		"tools":                schema.StringMap(schema.Any()),
		"containers":           schema.List(schema.StringMap(schema.Any())),
		"opened-ports":         schema.StringMap(schema.Any()),

		"provider-addresses":        schema.List(schema.StringMap(schema.Any())),
		"machine-addresses":         schema.List(schema.StringMap(schema.Any())),
		"preferred-public-address":  schema.StringMap(schema.Any()),
		"preferred-private-address": schema.StringMap(schema.Any()),

		"block-devices": schema.StringMap(schema.Any()),
	}

	defaults := schema.Defaults{
		"placement":      "",
		"container-type": "",
		// Even though we are expecting instance data for every machine,
		// it isn't strictly necessary, so we allow it to not exist here.
		"instance":                  schema.Omit,
		"supported-containers":      schema.Omit,
		"opened-ports":              schema.Omit,
		"block-devices":             schema.Omit,
		"provider-addresses":        schema.Omit,
		"machine-addresses":         schema.Omit,
		"preferred-public-address":  schema.Omit,
		"preferred-private-address": schema.Omit,
	}
	addAnnotationSchema(fields, defaults)
	addConstraintsSchema(fields, defaults)
	addStatusHistorySchema(fields)
	checker := schema.FieldMap(fields, defaults)

	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, errors.Annotatef(err, "machine v1 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.
	result := &machine{
		Id_:            valid["id"].(string),
		Nonce_:         valid["nonce"].(string),
		PasswordHash_:  valid["password-hash"].(string),
		Placement_:     valid["placement"].(string),
		Series_:        valid["series"].(string),
		ContainerType_: valid["container-type"].(string),
		StatusHistory_: newStatusHistory(),
		Jobs_:          convertToStringSlice(valid["jobs"]),
	}
	result.importAnnotations(valid)
	if err := result.importStatusHistory(valid); err != nil {
		return nil, errors.Trace(err)
	}

	if constraintsMap, ok := valid["constraints"]; ok {
		constraints, err := importConstraints(constraintsMap.(map[string]interface{}))
		if err != nil {
			return nil, errors.Trace(err)
		}
		result.Constraints_ = constraints
	}

	if supported, ok := valid["supported-containers"]; ok {
		supportedList := supported.([]interface{})
		s := make([]string, len(supportedList))
		for i, containerType := range supportedList {
			s[i] = containerType.(string)
		}
		result.SupportedContainers_ = &s
	}

	if instanceMap, ok := valid["instance"]; ok {
		instance, err := importCloudInstance(instanceMap.(map[string]interface{}))
		if err != nil {
			return nil, errors.Trace(err)
		}
		result.Instance_ = instance
	}

	if blockDeviceMap, ok := valid["block-devices"]; ok {
		devices, err := importBlockDevices(blockDeviceMap.(map[string]interface{}))
		if err != nil {
			return nil, errors.Trace(err)
		}
		result.setBlockDevices(devices)
	} else {
		result.setBlockDevices(nil)
	}

	// Tools and status are required, so we expect them to be there.
	tools, err := importAgentTools(valid["tools"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Trace(err)
	}
	result.Tools_ = tools

	status, err := importStatus(valid["status"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Trace(err)
	}
	result.Status_ = status

	if addresses, ok := valid["provider-addresses"]; ok {
		providerAddresses, err := importAddresses(addresses.([]interface{}))
		if err != nil {
			return nil, errors.Trace(err)
		}
		result.ProviderAddresses_ = providerAddresses
	}

	if addresses, ok := valid["machine-addresses"]; ok {
		machineAddresses, err := importAddresses(addresses.([]interface{}))
		if err != nil {
			return nil, errors.Trace(err)
		}
		result.MachineAddresses_ = machineAddresses
	}

	if address, ok := valid["preferred-public-address"]; ok {
		publicAddress, err := importAddress(address.(map[string]interface{}))
		if err != nil {
			return nil, errors.Trace(err)
		}
		result.PreferredPublicAddress_ = publicAddress
	}

	if address, ok := valid["preferred-private-address"]; ok {
		privateAddress, err := importAddress(address.(map[string]interface{}))
		if err != nil {
			return nil, errors.Trace(err)
		}
		result.PreferredPrivateAddress_ = privateAddress
	}

	machineList := valid["containers"].([]interface{})
	machines, err := importMachineList(machineList, importMachineV1)
	if err != nil {
		return nil, errors.Annotatef(err, "containers")
	}
	result.Containers_ = machines

	if portsMap, ok := valid["opened-ports"]; ok {
		portsList, err := importOpenedPorts(portsMap.(map[string]interface{}))
		if err != nil {
			return nil, errors.Trace(err)
		}
		result.setOpenedPorts(portsList)
	}

	return result, nil

}
コード例 #25
0
ファイル: model.go プロジェクト: AlexisBruemmer/juju
func importModelV1(source map[string]interface{}) (*model, error) {
	fields := schema.Fields{
		"owner":        schema.String(),
		"config":       schema.StringMap(schema.Any()),
		"latest-tools": schema.String(),
		"blocks":       schema.StringMap(schema.String()),
		"users":        schema.StringMap(schema.Any()),
		"machines":     schema.StringMap(schema.Any()),
		"services":     schema.StringMap(schema.Any()),
		"relations":    schema.StringMap(schema.Any()),
		"sequences":    schema.StringMap(schema.Int()),
	}
	// Some values don't have to be there.
	defaults := schema.Defaults{
		"latest-tools": schema.Omit,
		"blocks":       schema.Omit,
	}
	addAnnotationSchema(fields, defaults)
	addConstraintsSchema(fields, defaults)
	checker := schema.FieldMap(fields, defaults)

	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, errors.Annotatef(err, "model v1 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.

	result := &model{
		Version:    1,
		Owner_:     valid["owner"].(string),
		Config_:    valid["config"].(map[string]interface{}),
		Sequences_: make(map[string]int),
		Blocks_:    convertToStringMap(valid["blocks"]),
	}
	result.importAnnotations(valid)
	sequences := valid["sequences"].(map[string]interface{})
	for key, value := range sequences {
		result.SetSequence(key, int(value.(int64)))
	}

	if constraintsMap, ok := valid["constraints"]; ok {
		constraints, err := importConstraints(constraintsMap.(map[string]interface{}))
		if err != nil {
			return nil, errors.Trace(err)
		}
		result.Constraints_ = constraints
	}

	if availableTools, ok := valid["latest-tools"]; ok {
		num, err := version.Parse(availableTools.(string))
		if err != nil {
			return nil, errors.Trace(err)
		}
		result.LatestToolsVersion_ = num
	}

	userMap := valid["users"].(map[string]interface{})
	users, err := importUsers(userMap)
	if err != nil {
		return nil, errors.Annotate(err, "users")
	}
	result.setUsers(users)

	machineMap := valid["machines"].(map[string]interface{})
	machines, err := importMachines(machineMap)
	if err != nil {
		return nil, errors.Annotate(err, "machines")
	}
	result.setMachines(machines)

	serviceMap := valid["services"].(map[string]interface{})
	services, err := importServices(serviceMap)
	if err != nil {
		return nil, errors.Annotate(err, "services")
	}
	result.setServices(services)

	relationMap := valid["relations"].(map[string]interface{})
	relations, err := importRelations(relationMap)
	if err != nil {
		return nil, errors.Annotate(err, "relations")
	}
	result.setRelations(relations)

	return result, nil
}
コード例 #26
0
ファイル: volume.go プロジェクト: bac/juju
func importVolumeV1(source map[string]interface{}) (*volume, error) {
	fields := schema.Fields{
		"id":          schema.String(),
		"storage-id":  schema.String(),
		"binding":     schema.String(),
		"provisioned": schema.Bool(),
		"size":        schema.ForceUint(),
		"pool":        schema.String(),
		"hardware-id": schema.String(),
		"volume-id":   schema.String(),
		"persistent":  schema.Bool(),
		"status":      schema.StringMap(schema.Any()),
		"attachments": schema.StringMap(schema.Any()),
	}

	defaults := schema.Defaults{
		"storage-id":  "",
		"binding":     "",
		"pool":        "",
		"hardware-id": "",
		"volume-id":   "",
		"attachments": schema.Omit,
	}
	addStatusHistorySchema(fields)
	checker := schema.FieldMap(fields, defaults)

	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, errors.Annotatef(err, "volume v1 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.
	result := &volume{
		ID_:            valid["id"].(string),
		StorageID_:     valid["storage-id"].(string),
		Binding_:       valid["binding"].(string),
		Provisioned_:   valid["provisioned"].(bool),
		Size_:          valid["size"].(uint64),
		Pool_:          valid["pool"].(string),
		HardwareID_:    valid["hardware-id"].(string),
		VolumeID_:      valid["volume-id"].(string),
		Persistent_:    valid["persistent"].(bool),
		StatusHistory_: newStatusHistory(),
	}
	if err := result.importStatusHistory(valid); err != nil {
		return nil, errors.Trace(err)
	}

	status, err := importStatus(valid["status"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Trace(err)
	}
	result.Status_ = status

	attachments, err := importVolumeAttachments(valid["attachments"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Trace(err)
	}
	result.setAttachments(attachments)

	return result, nil
}
コード例 #27
0
ファイル: machine.go プロジェクト: voidspace/gomaasapi
func machine_2_0(source map[string]interface{}) (*machine, error) {
	fields := schema.Fields{
		"resource_uri": schema.String(),

		"system_id": schema.String(),
		"hostname":  schema.String(),
		"fqdn":      schema.String(),
		"tag_names": schema.List(schema.String()),

		"osystem":       schema.String(),
		"distro_series": schema.String(),
		"architecture":  schema.String(),
		"memory":        schema.ForceInt(),
		"cpu_count":     schema.ForceInt(),

		"ip_addresses":   schema.List(schema.String()),
		"power_state":    schema.String(),
		"status_name":    schema.String(),
		"status_message": schema.String(),

		"boot_interface": schema.StringMap(schema.Any()),
		"interface_set":  schema.List(schema.StringMap(schema.Any())),
		"zone":           schema.StringMap(schema.Any()),

		"physicalblockdevice_set": schema.List(schema.StringMap(schema.Any())),
		"blockdevice_set":         schema.List(schema.StringMap(schema.Any())),
	}
	checker := schema.FieldMap(fields, nil) // no defaults
	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, WrapWithDeserializationError(err, "machine 2.0 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.

	bootInterface, err := interface_2_0(valid["boot_interface"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Trace(err)
	}
	interfaceSet, err := readInterfaceList(valid["interface_set"].([]interface{}), interface_2_0)
	if err != nil {
		return nil, errors.Trace(err)
	}
	zone, err := zone_2_0(valid["zone"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Trace(err)
	}
	physicalBlockDevices, err := readBlockDeviceList(valid["physicalblockdevice_set"].([]interface{}), blockdevice_2_0)
	if err != nil {
		return nil, errors.Trace(err)
	}
	blockDevices, err := readBlockDeviceList(valid["blockdevice_set"].([]interface{}), blockdevice_2_0)
	if err != nil {
		return nil, errors.Trace(err)
	}

	result := &machine{
		resourceURI: valid["resource_uri"].(string),

		systemID: valid["system_id"].(string),
		hostname: valid["hostname"].(string),
		fqdn:     valid["fqdn"].(string),
		tags:     convertToStringSlice(valid["tag_names"]),

		operatingSystem: valid["osystem"].(string),
		distroSeries:    valid["distro_series"].(string),
		architecture:    valid["architecture"].(string),
		memory:          valid["memory"].(int),
		cpuCount:        valid["cpu_count"].(int),

		ipAddresses:   convertToStringSlice(valid["ip_addresses"]),
		powerState:    valid["power_state"].(string),
		statusName:    valid["status_name"].(string),
		statusMessage: valid["status_message"].(string),

		bootInterface:        bootInterface,
		interfaceSet:         interfaceSet,
		zone:                 zone,
		physicalBlockDevices: physicalBlockDevices,
		blockDevices:         blockDevices,
	}

	return result, nil
}
コード例 #28
0
ファイル: service.go プロジェクト: AlexisBruemmer/juju
func importServiceV1(source map[string]interface{}) (*service, error) {
	fields := schema.Fields{
		"name":                schema.String(),
		"series":              schema.String(),
		"subordinate":         schema.Bool(),
		"charm-url":           schema.String(),
		"cs-channel":          schema.String(),
		"charm-mod-version":   schema.Int(),
		"force-charm":         schema.Bool(),
		"exposed":             schema.Bool(),
		"min-units":           schema.Int(),
		"status":              schema.StringMap(schema.Any()),
		"settings":            schema.StringMap(schema.Any()),
		"settings-refcount":   schema.Int(),
		"leader":              schema.String(),
		"leadership-settings": schema.StringMap(schema.Any()),
		"metrics-creds":       schema.String(),
		"units":               schema.StringMap(schema.Any()),
	}

	defaults := schema.Defaults{
		"subordinate":   false,
		"force-charm":   false,
		"exposed":       false,
		"min-units":     int64(0),
		"leader":        "",
		"metrics-creds": "",
	}
	addAnnotationSchema(fields, defaults)
	addConstraintsSchema(fields, defaults)
	addStatusHistorySchema(fields)
	checker := schema.FieldMap(fields, defaults)

	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, errors.Annotatef(err, "service v1 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.
	result := &service{
		Name_:                 valid["name"].(string),
		Series_:               valid["series"].(string),
		Subordinate_:          valid["subordinate"].(bool),
		CharmURL_:             valid["charm-url"].(string),
		Channel_:              valid["cs-channel"].(string),
		CharmModifiedVersion_: int(valid["charm-mod-version"].(int64)),
		ForceCharm_:           valid["force-charm"].(bool),
		Exposed_:              valid["exposed"].(bool),
		MinUnits_:             int(valid["min-units"].(int64)),
		Settings_:             valid["settings"].(map[string]interface{}),
		SettingsRefCount_:     int(valid["settings-refcount"].(int64)),
		Leader_:               valid["leader"].(string),
		LeadershipSettings_:   valid["leadership-settings"].(map[string]interface{}),
		StatusHistory_:        newStatusHistory(),
	}
	result.importAnnotations(valid)
	if err := result.importStatusHistory(valid); err != nil {
		return nil, errors.Trace(err)
	}

	if constraintsMap, ok := valid["constraints"]; ok {
		constraints, err := importConstraints(constraintsMap.(map[string]interface{}))
		if err != nil {
			return nil, errors.Trace(err)
		}
		result.Constraints_ = constraints
	}

	encodedCreds := valid["metrics-creds"].(string)
	// The model stores the creds encoded, but we want to make sure that
	// we are storing something that can be decoded.
	if _, err := base64.StdEncoding.DecodeString(encodedCreds); err != nil {
		return nil, errors.Annotate(err, "metrics credentials not valid")
	}
	result.MetricsCredentials_ = encodedCreds

	status, err := importStatus(valid["status"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Trace(err)
	}
	result.Status_ = status

	units, err := importUnits(valid["units"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Trace(err)
	}
	result.setUnits(units)

	return result, nil
}
コード例 #29
0
ファイル: model.go プロジェクト: bac/juju
func importModelV1(source map[string]interface{}) (*model, error) {
	fields := schema.Fields{
		"owner":                schema.String(),
		"cloud":                schema.String(),
		"cloud-region":         schema.String(),
		"config":               schema.StringMap(schema.Any()),
		"latest-tools":         schema.String(),
		"blocks":               schema.StringMap(schema.String()),
		"users":                schema.StringMap(schema.Any()),
		"machines":             schema.StringMap(schema.Any()),
		"applications":         schema.StringMap(schema.Any()),
		"relations":            schema.StringMap(schema.Any()),
		"ssh-host-keys":        schema.StringMap(schema.Any()),
		"cloud-image-metadata": schema.StringMap(schema.Any()),
		"actions":              schema.StringMap(schema.Any()),
		"ip-addresses":         schema.StringMap(schema.Any()),
		"spaces":               schema.StringMap(schema.Any()),
		"subnets":              schema.StringMap(schema.Any()),
		"link-layer-devices":   schema.StringMap(schema.Any()),
		"volumes":              schema.StringMap(schema.Any()),
		"filesystems":          schema.StringMap(schema.Any()),
		"storages":             schema.StringMap(schema.Any()),
		"storage-pools":        schema.StringMap(schema.Any()),
		"sequences":            schema.StringMap(schema.Int()),
	}
	// Some values don't have to be there.
	defaults := schema.Defaults{
		"latest-tools": schema.Omit,
		"blocks":       schema.Omit,
		"cloud-region": schema.Omit,
	}
	addAnnotationSchema(fields, defaults)
	addConstraintsSchema(fields, defaults)
	checker := schema.FieldMap(fields, defaults)

	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, errors.Annotatef(err, "model v1 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.

	result := &model{
		Version:    1,
		Owner_:     valid["owner"].(string),
		Config_:    valid["config"].(map[string]interface{}),
		Sequences_: make(map[string]int),
		Blocks_:    convertToStringMap(valid["blocks"]),
		Cloud_:     valid["cloud"].(string),
	}
	result.importAnnotations(valid)
	sequences := valid["sequences"].(map[string]interface{})
	for key, value := range sequences {
		result.SetSequence(key, int(value.(int64)))
	}

	if constraintsMap, ok := valid["constraints"]; ok {
		constraints, err := importConstraints(constraintsMap.(map[string]interface{}))
		if err != nil {
			return nil, errors.Trace(err)
		}
		result.Constraints_ = constraints
	}

	if availableTools, ok := valid["latest-tools"]; ok {
		num, err := version.Parse(availableTools.(string))
		if err != nil {
			return nil, errors.Trace(err)
		}
		result.LatestToolsVersion_ = num
	}

	if region, ok := valid["cloud-region"]; ok {
		result.CloudRegion_ = region.(string)
	}

	if credential, ok := valid["cloud-credential"]; ok {
		result.CloudCredential_ = credential.(string)
	}

	userMap := valid["users"].(map[string]interface{})
	users, err := importUsers(userMap)
	if err != nil {
		return nil, errors.Annotate(err, "users")
	}
	result.setUsers(users)

	machineMap := valid["machines"].(map[string]interface{})
	machines, err := importMachines(machineMap)
	if err != nil {
		return nil, errors.Annotate(err, "machines")
	}
	result.setMachines(machines)

	applicationMap := valid["applications"].(map[string]interface{})
	applications, err := importApplications(applicationMap)
	if err != nil {
		return nil, errors.Annotate(err, "applications")
	}
	result.setApplications(applications)

	relationMap := valid["relations"].(map[string]interface{})
	relations, err := importRelations(relationMap)
	if err != nil {
		return nil, errors.Annotate(err, "relations")
	}
	result.setRelations(relations)

	spaceMap := valid["spaces"].(map[string]interface{})
	spaces, err := importSpaces(spaceMap)
	if err != nil {
		return nil, errors.Annotate(err, "spaces")
	}
	result.setSpaces(spaces)

	deviceMap := valid["link-layer-devices"].(map[string]interface{})
	devices, err := importLinkLayerDevices(deviceMap)
	if err != nil {
		return nil, errors.Annotate(err, "link-layer-devices")
	}
	result.setLinkLayerDevices(devices)

	subnetsMap := valid["subnets"].(map[string]interface{})
	subnets, err := importSubnets(subnetsMap)
	if err != nil {
		return nil, errors.Annotate(err, "subnets")
	}
	result.setSubnets(subnets)

	addressMap := valid["ip-addresses"].(map[string]interface{})
	addresses, err := importIPAddresses(addressMap)
	if err != nil {
		return nil, errors.Annotate(err, "ip-addresses")
	}
	result.setIPAddresses(addresses)

	sshHostKeyMap := valid["ssh-host-keys"].(map[string]interface{})
	hostKeys, err := importSSHHostKeys(sshHostKeyMap)
	if err != nil {
		return nil, errors.Annotate(err, "ssh-host-keys")
	}
	result.setSSHHostKeys(hostKeys)

	cloudimagemetadataMap := valid["cloud-image-metadata"].(map[string]interface{})
	cloudimagemetadata, err := importCloudImageMetadata(cloudimagemetadataMap)
	if err != nil {
		return nil, errors.Annotate(err, "cloud-image-metadata")
	}
	result.setCloudImageMetadatas(cloudimagemetadata)

	actionsMap := valid["actions"].(map[string]interface{})
	actions, err := importActions(actionsMap)
	if err != nil {
		return nil, errors.Annotate(err, "actions")
	}
	result.setActions(actions)

	volumes, err := importVolumes(valid["volumes"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Annotate(err, "volumes")
	}
	result.setVolumes(volumes)

	filesystems, err := importFilesystems(valid["filesystems"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Annotate(err, "filesystems")
	}
	result.setFilesystems(filesystems)

	storages, err := importStorages(valid["storages"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Annotate(err, "storages")
	}
	result.setStorages(storages)

	pools, err := importStoragePools(valid["storage-pools"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Annotate(err, "storage-pools")
	}
	result.setStoragePools(pools)

	return result, nil
}
コード例 #30
0
ファイル: unit.go プロジェクト: AlexisBruemmer/juju
func importUnitV1(source map[string]interface{}) (*unit, error) {
	fields := schema.Fields{
		"name":    schema.String(),
		"machine": schema.String(),

		"agent-status":            schema.StringMap(schema.Any()),
		"agent-status-history":    schema.StringMap(schema.Any()),
		"workload-status":         schema.StringMap(schema.Any()),
		"workload-status-history": schema.StringMap(schema.Any()),

		"principal":    schema.String(),
		"subordinates": schema.List(schema.String()),

		"password-hash": schema.String(),
		"tools":         schema.StringMap(schema.Any()),

		"meter-status-code": schema.String(),
		"meter-status-info": schema.String(),
	}
	defaults := schema.Defaults{
		"principal":         "",
		"subordinates":      schema.Omit,
		"meter-status-code": "",
		"meter-status-info": "",
	}
	addAnnotationSchema(fields, defaults)
	addConstraintsSchema(fields, defaults)
	checker := schema.FieldMap(fields, defaults)

	coerced, err := checker.Coerce(source, nil)
	if err != nil {
		return nil, errors.Annotatef(err, "unit v1 schema check failed")
	}
	valid := coerced.(map[string]interface{})
	// From here we know that the map returned from the schema coercion
	// contains fields of the right type.

	result := &unit{
		Name_:                  valid["name"].(string),
		Machine_:               valid["machine"].(string),
		Principal_:             valid["principal"].(string),
		PasswordHash_:          valid["password-hash"].(string),
		MeterStatusCode_:       valid["meter-status-code"].(string),
		MeterStatusInfo_:       valid["meter-status-info"].(string),
		WorkloadStatusHistory_: newStatusHistory(),
		AgentStatusHistory_:    newStatusHistory(),
	}
	result.importAnnotations(valid)

	workloadHistory := valid["workload-status-history"].(map[string]interface{})
	if err := importStatusHistory(&result.WorkloadStatusHistory_, workloadHistory); err != nil {
		return nil, errors.Trace(err)
	}
	agentHistory := valid["agent-status-history"].(map[string]interface{})
	if err := importStatusHistory(&result.AgentStatusHistory_, agentHistory); err != nil {
		return nil, errors.Trace(err)
	}

	if constraintsMap, ok := valid["constraints"]; ok {
		constraints, err := importConstraints(constraintsMap.(map[string]interface{}))
		if err != nil {
			return nil, errors.Trace(err)
		}
		result.Constraints_ = constraints
	}

	result.Subordinates_ = convertToStringSlice(valid["subordinates"])

	// Tools and status are required, so we expect them to be there.
	tools, err := importAgentTools(valid["tools"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Trace(err)
	}
	result.Tools_ = tools

	agentStatus, err := importStatus(valid["agent-status"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Trace(err)
	}
	result.AgentStatus_ = agentStatus

	workloadStatus, err := importStatus(valid["workload-status"].(map[string]interface{}))
	if err != nil {
		return nil, errors.Trace(err)
	}
	result.WorkloadStatus_ = workloadStatus

	return result, nil
}